Python for Java people

Editor's note: in the Java channel, most of us know the language very well and have worked in its ecosystem for at least a few years. This gives us routine and expertise, but it also gives rise to a certain degree of tunnel vision. Outside in Java In this series, non javanists will show us their views on ecosystems.

catalogue

Philosophically speaking, Python is almost the opposite of Java. Instead of static typing and rigid structure, it is a loose sandbox in which you can freely do whatever you want. Maybe Python is about what you can do, and Java is about what you can do.

However, both languages still have a lot of inspiration that can be traced back to C. They are all imperative languages with block, loop, function, assignment and infix mathematics. Both make extensive use of classes, objects, inheritance, and polymorphism. Both have quite prominent anomalies. Both automatically handle memory management. They are even compiled as bytecode running on the VM, although Python compiles transparently for you. Python even drew some clues from Java -- the standard library logging and unittest The module is inspired by log4j and JUnit respectively.

Given this overlap, I think Java developers should feel at home with Python. So I came to you with some gentle Python propaganda. If you give me a chance, I can show you the differences between Python and Java and why I find these differences attractive. At the very least, you may find some interesting ideas that can be brought back to the Java ecosystem.

(if you want a Python tutorial, the Python documentation has a very good . In addition, this is from the perspective of Python 3! Python 2 is still quite common in the wild, with some syntax differences.)

syntax

Let's solve this problem first. This is Hello World:

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">print<span style="color:#c792ea">(</span><span style="color:#c3e88d">"Hello, world!"</span><span style="color:#c792ea">)</span>
</code></span></span>

Well, well, it's not very enlightening. OK, this is a function to find the ten most commonly used words in the file. I use the standard library Counter The type is a little cheating, but it's really great.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">from collections import Counter

def <span style="color:#82aaff">count_words</span><span style="color:#c792ea">(</span>path<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    words <span style="color:#89ddff">=</span> Counter<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span>
    with <span style="color:#82aaff">open</span><span style="color:#c792ea">(</span>path<span style="color:#c792ea">)</span> as f<span style="color:#c792ea">:</span>
        for line in f<span style="color:#c792ea">:</span>
            for word in line<span style="color:#c792ea">.</span>strip<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span><span style="color:#c792ea">.</span>split<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
                words<span style="color:#c792ea">[</span>word<span style="color:#c792ea">]</span> <span style="color:#89ddff">+=</span> <span style="color:#f78c6c">1</span>

    for word<span style="color:#c792ea">,</span> count in words<span style="color:#c792ea">.</span>most_common<span style="color:#c792ea">(</span><span style="color:#f78c6c">10</span><span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
        print<span style="color:#c792ea">(</span><span style="color:#c3e88d">f"</span><span style="color:#c792ea">{</span>word<span style="color:#c792ea">}</span><span style="color:#c3e88d"> x</span><span style="color:#c792ea">{</span>count<span style="color:#c792ea">}</span><span style="color:#c3e88d">"</span><span style="color:#c792ea">)</span>
</code></span></span>

Python is separated by spaces. People often have strong views on this. When I first saw it, I even thought it was heresy. Now, about ten years later, it seems so natural that it's hard for me to put on braces again. If you are tired of it, I doubt I can convince you, but I urge you to ignore it at least for the time being; It does not cause any serious problems in practice, and it eliminates a considerable amount of noise. In addition, python developers never have to argue a{where to go.

If you are interested in Python and want to learn more about Python and AIoT, solve testing problems, and get started guide to help you solve the puzzles encountered in learning python, we have technical experts here. If you are looking for a job, have just come out of school, or have worked, but often feel that there are many difficulties, feel that you are not proficient enough in Python, and want to continue learning. If you want to change careers, you are afraid that you won't learn, you can join us and get the latest interview materials of Python manufacturers and python crawlers, artificial intelligence and learning materials! WeChat official account [Python base] waiting for you to play Austrian.

In addition to this aesthetic difference, most of them should look familiar. We have some numbers, some assignments, and some method calls. The import declaration works slightly differently, but it has the same general meaning of "making this thing available". Python's loop is very similar to Java's - each loop for, except for a little less punctuation. The for function itself is separated by def rather than type, but it works as you expect: you can call it with parameters and return a value (although this one doesn't).

There are only two things that are very unusual. One is the with block, which is very similar to "with resources" in Java 7. try -- it guarantees that the file will be closed at the end of the block, even if an exception is thrown in it. The other is f "..." Syntax, a fairly new feature that allows expressions to be inserted directly into strings.

this is it! You have read some Python. At least, this is not a language from a completely different planet.

Dynamic type

It may be obvious from this example, but Python code does not have many types. Not on variable declarations, not on parameters or return types, not on the layout of objects. Anything can be of any type at any time. I haven't shown a class definition yet, so here's a trivial definition.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">class <span style="color:#ffcb6b">Point</span><span style="color:#c792ea">:</span>
    def <span style="color:#82aaff">__init__</span><span style="color:#c792ea">(</span>self<span style="color:#c792ea">,</span> x<span style="color:#c792ea">,</span> y<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
        self<span style="color:#c792ea">.</span>x <span style="color:#89ddff">=</span> x
        self<span style="color:#c792ea">.</span>y <span style="color:#89ddff">=</span> y

    def <span style="color:#82aaff">magnitude</span><span style="color:#c792ea">(</span>self<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
        return <span style="color:#c792ea">(</span>self<span style="color:#c792ea">.</span>x <span style="color:#89ddff">**</span> <span style="color:#f78c6c">2</span> <span style="color:#89ddff">+</span> self<span style="color:#c792ea">.</span>y <span style="color:#89ddff">**</span> <span style="color:#f78c6c">2</span><span style="color:#c792ea">)</span> <span style="color:#89ddff">**</span> <span style="color:#f78c6c">0.5</span>

point <span style="color:#89ddff">=</span> Point<span style="color:#c792ea">(</span><span style="color:#f78c6c">3</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">4</span><span style="color:#c792ea">)</span>
print<span style="color:#c792ea">(</span>point<span style="color:#c792ea">.</span>x<span style="color:#c792ea">)</span>  <span style="color:#697098"># 3</span>
print<span style="color:#c792ea">(</span>point<span style="color:#c792ea">.</span>magnitude<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span><span style="color:#c792ea">)</span>  <span style="color:#697098"># 5.0</span>
</code></span></span>

Even xandy is not declared as an attribute; They exist because constructors create them. Nothing forces me to pass in integers. I could have passed in floating-point numbers, or maybe Decimals or Fractions.

This may sound confusing if you only use static languages. Type warm, comfortable and comfortable. They promised Well, maybe the code doesn't really work (although Some people disagree ), but there are some things. How can you rely on code when you don't even know that anything is of the right type?

But wait -- Java has no such guarantee! After all, any object can be null, right? This is almost never the right type of object.

You might think that dynamic typing is a complete solution to the problem. If we have to deal with it anyway, we might as well accept it and let it work for us - by delaying all running time. Type errors become normal logical errors, and you deal with them in the same way.

(for the opposite method, see Rust , it has no null value or exception. I still prefer to write Python, but I appreciate Rust's type system and don't always lie to me quietly.)

In my method, int or float or any type of number doesn't matter. self.x it only needs to support * * operators and return things that support + operators. (Python supports operator overloading, so this can be anything.) The same applies to normal method calls: any type is acceptable as long as it works in practice.

This means that Python does not require generics. Everything is working properly. No interface is required; Everything is already polymorphic. In the type system, there is no down conversion, no up conversion, and no escape hatch. There will be no need when the List can be associated with any Iterable

Many common patterns become much easier. You can create wrapper objects and proxies without changing the usage code. You can use composition instead of inheritance to extend third-party types - you don't need to do anything special to maintain polymorphism. Flexible API does not need to copy every class as an interface; Everything has acted as an implicit interface.

Dynamic typing Philosophy

With static types, anyone who writes code can choose types, and the compiler checks whether they work. With dynamic typing, anyone who uses some code can choose the type and will try it at run time. This is the opposite philosophy: the type system focuses on what you can do, not what you can do.

Using dynamic types in this way is sometimes called "duck type", which means "if it walks like a duck and it quacks like a duck, it's a duck". The idea is that if all you want is a quack, don't statically force your code to receive ducks. You can take anything you get and let it quack. If so, anyway, that's what you care about, so it's as good as a duck. (if not, you'll get an AttributeError, but it's not very powerful.)

Note that Python is still strongly typed. The term is a bit vague, but it usually means that values retain their types at run time. A typical example is that Python does not allow you to add strings to numbers, and weakly typed languages such as JavaScript use priority rules that may not meet your expectations Silently convert one type to another.

Unlike many dynamic languages, Python tends to find errors early -- at run time anyway. For example, reading a Map from a non-existent variable will throw an exception, and reading a non-existent key from dict (such as a) will also throw an exception. In JavaScript, Lua and similar languages, you get a value silently in both cases. (even Java will return null due to the lack of Map key!) If you want to go back to the default value, dicts has a way to express it more clearly.

There must be a trade-off. Whether it is worth it varies from project to individual. At least for me, after I see the actual design of a system, it is easier to determine the design of a system, but statically typed languages need to be designed in advance. Static typing makes it harder and harder to try many different ideas.

You do have less static assurance, but in my experience, most types of errors are caught immediately Because the first thing I do after writing some code is try to run it! Everything else should be captured by your tests - you should write in any language, and Python makes it relatively easy.

Mixed paradigm

Python and Java are both imperative and object-oriented: they work by executing instructions and modeling everything as objects.

In the recent version, Java has added some features, which I think is very cheering. Python also has quite a number of functional features, but... The method is somewhat different. map provides some token built-in reduce functions like and, but it is not really designed around the idea of linking many small functions together.

Instead, Python is mixed with... Something else. I don't know the common name of the method used by python. I think it divides the idea of "linking functions" into two parts: using sequences and making the function itself more powerful.

sequence

Sequences and iterations play an important role in Python. Sequences can be said to be the most basic data structure, so the tools to use them are very good. I interpret this as Python's alternative to functional programming: instead of making it easier to combine many small functions and then apply them to sequences, python makes it easier to manipulate sequences first with imperative code.

Back at the beginning, I fell into this line:

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">    for word<span style="color:#c792ea">,</span> count in words<span style="color:#c792ea">.</span>most_common<span style="color:#c792ea">(</span><span style="color:#f78c6c">10</span><span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
</code></span></span>

Loops are familiar, but this code iterates two variables at a time. What actually happens is that each element in the list is most_common returns a tuple, a set of sequentially distinguished values. Tuples can be unpacked by assigning them to tuples of variable names, which is what really happens here. Tuples are often used to return multiple values in Python, but they are sometimes useful in temporary structures. In Java, you need a complete class and a few lines of distribution.

Anything that can be iterated can also be unpacked. Unpacking supports arbitrary nesting, a, (b, c) = It looks the same. For sequences of unknown length, a * leftovers element can appear anywhere, and will absorb as many elements as necessary. Maybe you really like LISP?

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">values <span style="color:#89ddff">=</span> <span style="color:#c792ea">[</span><span style="color:#f78c6c">5</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">7</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">9</span><span style="color:#c792ea">]</span>
head<span style="color:#c792ea">,</span> <span style="color:#89ddff">*</span>tail <span style="color:#89ddff">=</span> values
print<span style="color:#c792ea">(</span>head<span style="color:#c792ea">)</span>  <span style="color:#697098"># 5</span>
print<span style="color:#c792ea">(</span>tail<span style="color:#c792ea">)</span>  <span style="color:#697098"># (7, 9)</span>
</code></span></span>

Python also has a syntax for creating lists from simple expressions - the so-called "list derivation" - which is similar to the syntax for creating dicts and set s than functional methods such as map. The whole loop can be simplified into an expression that emphasizes what you are really interested in.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">values <span style="color:#89ddff">=</span> <span style="color:#c792ea">[</span><span style="color:#f78c6c">3</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">4</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">5</span><span style="color:#c792ea">]</span>
values2 <span style="color:#89ddff">=</span> <span style="color:#c792ea">[</span>val <span style="color:#89ddff">*</span> <span style="color:#f78c6c">2</span> for val in values if val <span style="color:#89ddff">!=</span> <span style="color:#f78c6c">4</span><span style="color:#c792ea">]</span>
print<span style="color:#c792ea">(</span>values2<span style="color:#c792ea">)</span>  <span style="color:#697098"># [6, 10]</span>
</code></span></span>

The standard library is still there itertools Modules contain many interesting iterators, composers, and recipes.

Finally, Python has a generator that generates lazy sequences using imperative code. The function containing the yield keyword will not be executed immediately when called; Instead, it returns a generator object. When the generator is iterated, the function will run until it meets a # yield, at which time it will pause; The resulting value becomes the next iteration value.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">def <span style="color:#82aaff">odd_numbers</span><span style="color:#c792ea">(</span><span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    n <span style="color:#89ddff">=</span> <span style="color:#f78c6c">1</span>
    while <span style="color:#ff5874">True</span><span style="color:#c792ea">:</span>
        yield n
        n <span style="color:#89ddff">+=</span> <span style="color:#f78c6c">2</span>

for x in odd_numbers<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    print<span style="color:#c792ea">(</span>x<span style="color:#c792ea">)</span>
    if x <span style="color:#89ddff">></span> <span style="color:#f78c6c">4</span><span style="color:#c792ea">:</span>
        break
<span style="color:#697098"># 1</span>
<span style="color:#697098"># 3</span>
<span style="color:#697098"># 5</span>
</code></span></span>

Because generators run late, they can produce infinite sequences or midway interrupts. They can generate a large number of large objects at the same time without consuming a lot of memory. They can also be used as a general alternative to "chained" functional programming. Instead of combining maps and filters, you can write familiar imperative code.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python"><span style="color:#697098"># This is the pathlib.Path API from the standard library</span>
def <span style="color:#82aaff">iter_child_filenames</span><span style="color:#c792ea">(</span>dirpath<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    for child in dirpath<span style="color:#c792ea">.</span>iterdir<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
        if child<span style="color:#c792ea">.</span>is_file<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
            yield child<span style="color:#c792ea">.</span>name
</code></span></span>

To express a completely arbitrary lazy Iterator in Java, you need to write an Iterator whose state Iterator manually tracks. For all but the simplest cases, this can become very tricky. Python also has an iteration interface, so you can still use this method, but generators are very easy to use and most custom iterations are written with them.

Because generators can pause themselves, they are also useful in other situations. By manually pushing the generator (rather than just iterating over for once through a loop), you can run a function halfway, stop it at some point, and run other code before restoring the function. Python takes advantage of this by adding pairs purely as a library Asynchronous I/O (non blocking networks without threads), although it now has dedicated async and await syntax.

function

At first glance, python functions are familiar. You can call them with parameters. The delivery style is exactly the same as in Java -- Python has neither references nor implicit copies. Python even has a "document string", similar to Javadoc annotations, but built into the syntax and readable at run time.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">def <span style="color:#82aaff">foo</span><span style="color:#c792ea">(</span>a<span style="color:#c792ea">,</span> b<span style="color:#c792ea">,</span> c<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    <span style="color:#c3e88d">"""Print out the arguments.  Not a very useful function, really."""</span>
    print<span style="color:#c792ea">(</span><span style="color:#c3e88d">"I got"</span><span style="color:#c792ea">,</span> a<span style="color:#c792ea">,</span> b<span style="color:#c792ea">,</span> c<span style="color:#c792ea">)</span>

foo<span style="color:#c792ea">(</span><span style="color:#f78c6c">1</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">2</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">3</span><span style="color:#c792ea">)</span>  <span style="color:#697098"># I got 1 2 3</span>
</code></span></span>

Java with args Variable parameter function of syntax; Python uses * args (* the unpacking syntax of leftovers is inspired by the function syntax.) But Python has some tricks. Any parameter can have a default value, making it optional. Any parameter can also be given by name - I used Point(x=3, y=4) When calling any function of * args, you can use this syntax to pass the sequence as if it were a separate parameter, and there is an equivalent that can accept or pass the named parameter as dict. The parameter can be set to keyword only, so it must be passed by name, which is good for optional Boolean values** kwargs

Of course, Python has no function overloading, but most of what you use it can be replaced with duck types and optional parameters.

You are now ready for one of Python's most powerful features. Very similar to dynamic types, you can transparently replace objects through wrappers or proxies, * args and * * kwargs allow any function to be transparently wrapped.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">def <span style="color:#82aaff">log_calls</span><span style="color:#c792ea">(</span>old_function<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    def <span style="color:#82aaff">new_function</span><span style="color:#c792ea">(</span><span style="color:#89ddff">*</span>args<span style="color:#c792ea">,</span> <span style="color:#89ddff">**</span>kwargs<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
        print<span style="color:#c792ea">(</span><span style="color:#c3e88d">"i'm being called!"</span><span style="color:#c792ea">,</span> args<span style="color:#c792ea">,</span> kwargs<span style="color:#c792ea">)</span>
        return old_function<span style="color:#c792ea">(</span><span style="color:#89ddff">*</span>args<span style="color:#c792ea">,</span> <span style="color:#89ddff">**</span>kwargs<span style="color:#c792ea">)</span>

    return new_function

<span style="color:#c792ea">@log_calls</span>
def <span style="color:#82aaff">foo</span><span style="color:#c792ea">(</span>a<span style="color:#c792ea">,</span> b<span style="color:#c792ea">,</span> c<span style="color:#89ddff">=</span><span style="color:#f78c6c">3</span><span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    print<span style="color:#c792ea">(</span><span style="color:#c3e88d">f"a = </span><span style="color:#c792ea">{</span>a<span style="color:#c792ea">}</span><span style="color:#c3e88d">, b = </span><span style="color:#c792ea">{</span>b<span style="color:#c792ea">}</span><span style="color:#c3e88d">, c = </span><span style="color:#c792ea">{</span>c<span style="color:#c792ea">}</span><span style="color:#c3e88d">"</span><span style="color:#c792ea">)</span>

foo<span style="color:#c792ea">(</span><span style="color:#f78c6c">1</span><span style="color:#c792ea">,</span> b<span style="color:#89ddff">=</span><span style="color:#f78c6c">2</span><span style="color:#c792ea">)</span>
<span style="color:#697098"># i'm being called! (1,) {'b': 2}</span>
<span style="color:#697098"># a = 1, b = 2, c = 3</span>
</code></span></span>

It's a little thick. I'm sorry. Don't worry too much about how it works; The point is that it foo is replaced by a new_function, which forwards all parameters to foo. Neither the caller nor the caller foo needs to know the difference.

I can't underestimate how powerful this is. It can be used for recording, debugging, resource management, caching, access control, verification, etc. It works very well with other metaprogramming functions, and in a similar way, it allows you to decompose structures rather than just code.

Object and dynamic runtime

Dynamic runtime is a runtime -- something behind the scenes that supports the core of the language -- that can be used at runtime. Languages like C or C + + have very little dynamic runtime; The structure of the source code is "baked" into the compiled output, and there is no wise way to change its behavior in the future. On the other hand, Java does have a dynamic runtime! It even comes with a package dedicated to reflection.

Of course, Python also has reflections. Many simple functions are built in to dynamically check or modify the properties of objects, which is very useful for debugging and occasional pranks.

But Python goes further. Since everything is done at runtime anyway, python exposes many extension points to customize its semantics. You can't change the syntax, so the code still looks like python, but you can usually decompose the structure -- which is difficult to do in a more rigorous language.

To take an extreme example, look pytest , it does very clever things with Python's assert statement. In general, writing assert x == 1 will only throw an error at the time of the error, so that you have no context about where or where the error occurred. This is why Python's built-in unittest module (such as JUnit and many other testing tools) provides a bunch of specific practical functions, such as assertEquals Unfortunately, these make testing more lengthy and difficult to see at a glance. But use pytestassert x == 1. If it fails, pytest will tell you what x is... Or where the two lists differ, or what elements are different between the two sets, or what you have. All this happens automatically based on the comparison in progress and the type of operand.

How does pytest work? You really don't want to know. And you don't have to know how to write tests using pytest -- and you can enjoy it.

This is the real advantage of dynamic runtime. These features may not be available to you personally. But you can get huge benefits from the libraries that use them, regardless of how they work. Even Python itself implements many additional functions with its own extension points -- no changes to the syntax or interpreter are required.

object

My favorite simple example is property access. In Java, the Point class may choose getX() and setX() methods instead of ordinary x attributes. The reason is that if you need to change the way x reads or writes, you can do so without breaking the interface. In Python, you don't have to worry about this in advance, because you can block attribute access if necessary.

If you are interested in Python and want to learn more about Python and AIoT, solve testing problems, and get started guide to help you solve the puzzles encountered in learning python, we have technical experts here. If you are looking for a job, have just come out of school, or have worked, but often feel that there are many difficulties, feel that you are not proficient enough in Python, and want to continue learning. If you want to change careers, you are afraid that you won't learn, you can join us and get the latest interview materials of Python manufacturers and python crawlers, artificial intelligence and learning materials! WeChat official account [Python base] waiting for you to play Austrian.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">class <span style="color:#ffcb6b">Point</span><span style="color:#c792ea">:</span>
    def <span style="color:#82aaff">__init__</span><span style="color:#c792ea">(</span>self<span style="color:#c792ea">,</span> x<span style="color:#c792ea">,</span> y<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
        self<span style="color:#c792ea">.</span>_x <span style="color:#89ddff">=</span> x
        self<span style="color:#c792ea">.</span>_y <span style="color:#89ddff">=</span> y

    <span style="color:#c792ea">@property</span>
    def <span style="color:#82aaff">x</span><span style="color:#c792ea">(</span>self<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
        return self<span style="color:#c792ea">.</span>_x

    <span style="color:#697098"># ... same for y ...</span>

point <span style="color:#89ddff">=</span> Point<span style="color:#c792ea">(</span><span style="color:#f78c6c">3</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">4</span><span style="color:#c792ea">)</span>
print<span style="color:#c792ea">(</span>point<span style="color:#c792ea">.</span>x<span style="color:#c792ea">)</span>  <span style="color:#697098"># 3</span>
</code></span></span>

The interesting @ property syntax is the decorator, which looks like a Java annotation, but can modify functions or classes more directly.

Readingpoint.x now calls a function and calculates its return value. This is completely transparent to the calling code -- and no different from any other property read -- but the object can intervene and handle it at will. Unlike Java, attribute access is part of the class API and can be customized freely. (please note that this example is also x read-only, because I didn't specify how to write it! The writable syntax property looks a little funny, and the way it works is not important here. But you can be insignificant, for example, forcing only odd numbers to be assigned to point.x.)

Similar features exist in other static languages such as C#, so this may not be so impressive. The really interesting part about Python is that its property is not special at all. It is a common built-in type that can be written in pure Python in less than one screen. It works because Python classes can customize their own attribute access, including general attribute access and each attribute access. Wrappers, proxies, and combinations are easy to implement: you can forward all method calls to the underlying object without knowing what methods it has.

The same hook property can be used for Deferred load properties or Automatically save properties of weak references ——Completely transparent to the calling code, and all from pure Python.

You may have noticed by now that my code does not have the publicorprivate modifier, and Python does not have such a concept. By convention, a single leading underscore is used to indicate "private" -- or, more accurately, "not intended to be part of a stable public API". But this has no semantic meaning, and Python itself does not prevent anyone from checking or changing such a property (or calling it if it is a method). Not final or static or const, either.

This works the same way: Core Python usually doesn't prevent you from doing anything. It's very useful when you need it. I fix errors in third-party libraries by calling or overriding or even completely redefining private methods at startup. It eliminates the need to create the entire local branch of the project. Once the upstream fixes the error, I just need to delete my patch code.

Similarly, you can easily write tests for code that depends on an external state, such as the current time. If refactoring is impractical, you can use time Time() is replaced with a virtual function during the test. Library functions are just properties of modules (such as Java packages), and Python modules are objects like anything else, so you can check and modify them in the same way.

curriculum

Java classes are supported by a Class object, but the two are not completely interchangeable. For a Class Foo, the Class object is Foo Class. I don't think Foo can use it alone because it names a type, and Java makes some subtle distinctions between types and values.

In Python, a class is an object and an instance type (it is an object itself, so it is an instance itself, which is interesting.) Therefore, a class can be treated like any other value: passed as a parameter, stored in a larger structure, checked or manipulated. The ability to make a dictionary of key classes is sometimes particularly useful. And because classes are instantiated by calling them -- Python doesn't have the new keyword -- in many cases they can be interchanged with simple functions. Some common patterns like factories are very simple and almost disappear.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python"><span style="color:#697098"># Wait, is Vehicle a class or a factory function?  Who cares!</span>
<span style="color:#697098"># It could even be changed from one to the other without breaking this code.</span>
car <span style="color:#89ddff">=</span> Vehicle<span style="color:#c792ea">(</span>wheels<span style="color:#89ddff">=</span><span style="color:#f78c6c">4</span><span style="color:#c792ea">,</span> doors<span style="color:#89ddff">=</span><span style="color:#f78c6c">4</span><span style="color:#c792ea">)</span>
</code></span></span>

Several times now, I put functions and even regular code at the top level outside of any class. This is allowed, but the meaning is a little subtle. In Python, even the classand statement is regular code that is executed at run time def. Python files execute from top to bottom and are not special in this regard. They are just special syntax for creating certain types of objects: classes and functions. classdef

This is a very cool part. Because classes are objects and their type is type, you can subclass {type and change how it works. You can then create a class that is an instance of a subclass.

It's a little strange to wrap your head around at first. But again, you don't need to know how it benefits. For example, Python does not have an enum block, but it does have one enum module:

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">class <span style="color:#ffcb6b">Animal</span><span style="color:#c792ea">(</span>Enum<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    cat <span style="color:#89ddff">=</span> <span style="color:#f78c6c">0</span>
    dog <span style="color:#89ddff">=</span> <span style="color:#f78c6c">1</span>
    mouse <span style="color:#89ddff">=</span> <span style="color:#f78c6c">2</span>
    snake <span style="color:#89ddff">=</span> <span style="color:#f78c6c">3</span>

print<span style="color:#c792ea">(</span>Animal<span style="color:#c792ea">.</span>cat<span style="color:#c792ea">)</span>           <span style="color:#697098"># <Animal.cat: 0></span>
print<span style="color:#c792ea">(</span>Animal<span style="color:#c792ea">.</span>cat<span style="color:#c792ea">.</span>value<span style="color:#c792ea">)</span>     <span style="color:#697098"># 0</span>
print<span style="color:#c792ea">(</span>Animal<span style="color:#c792ea">(</span><span style="color:#f78c6c">2</span><span style="color:#c792ea">)</span><span style="color:#c792ea">)</span>            <span style="color:#697098"># <Animal.mouse: 2></span>
print<span style="color:#c792ea">(</span>Animal<span style="color:#c792ea">[</span><span style="color:#c3e88d">'dog'</span><span style="color:#c792ea">]</span><span style="color:#c792ea">)</span>        <span style="color:#697098"># <Animal.dog: 1></span>
</code></span></span>

The class statement creates an object, which means that it calls a constructor somewhere, and the constructor can be overridden to change how the class is built. Here, Enum creates a fixed set of instances instead of class properties. All of these are implemented in pure Python code and normal Python syntax.

The whole library is built on these ideas. Do you hate self Foo = foo type tedious content for each attribute in the constructor? Then manually define equality, hashing and cloning, and developer readable representations? Java requires compiler support, which may be different from Project Amber Together. Python is flexible enough for the community to use attrs Library solves this problem.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">import attr

<span style="color:#c792ea">@attr<span style="color:#c792ea">.</span>s</span>
class <span style="color:#ffcb6b">Point</span><span style="color:#c792ea">:</span>
    x <span style="color:#89ddff">=</span> attr<span style="color:#c792ea">.</span>ib<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span>
    y <span style="color:#89ddff">=</span> attr<span style="color:#c792ea">.</span>ib<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span>

p <span style="color:#89ddff">=</span> Point<span style="color:#c792ea">(</span><span style="color:#f78c6c">3</span><span style="color:#c792ea">,</span> <span style="color:#f78c6c">4</span><span style="color:#c792ea">)</span>
q <span style="color:#89ddff">=</span> Point<span style="color:#c792ea">(</span>x<span style="color:#89ddff">=</span><span style="color:#f78c6c">3</span><span style="color:#c792ea">,</span> y<span style="color:#89ddff">=</span><span style="color:#f78c6c">4</span><span style="color:#c792ea">)</span>
p <span style="color:#89ddff">==</span> q  <span style="color:#697098"># True, which it wouldn't have been before!</span>
print<span style="color:#c792ea">(</span>p<span style="color:#c792ea">)</span>  <span style="color:#697098"># Point(x=3, y=4)</span>
</code></span></span>

Or use SQLAlchemy , this is a powerful database library for Python. It contains a Hibernate supported by Java Inspired ORM, but not in the configuration file or through some lengthy comments to declare the schema of the table, you can write it directly as a class:

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">class <span style="color:#ffcb6b">Order</span><span style="color:#c792ea">(</span>Table<span style="color:#c792ea">)</span><span style="color:#c792ea">:</span>
    <span style="color:#82aaff">id</span> <span style="color:#89ddff">=</span> Column<span style="color:#c792ea">(</span>Integer<span style="color:#c792ea">,</span> primary_key<span style="color:#89ddff">=</span><span style="color:#ff5874">True</span><span style="color:#c792ea">)</span>
    order_number <span style="color:#89ddff">=</span> Column<span style="color:#c792ea">(</span>Integer<span style="color:#c792ea">,</span> index<span style="color:#89ddff">=</span><span style="color:#ff5874">True</span><span style="color:#c792ea">)</span>
    status <span style="color:#89ddff">=</span> Column<span style="color:#c792ea">(</span>Enum<span style="color:#c792ea">(</span><span style="color:#c3e88d">'pending'</span><span style="color:#c792ea">,</span> <span style="color:#c3e88d">'complete'</span><span style="color:#c792ea">)</span><span style="color:#c792ea">,</span> default<span style="color:#89ddff">=</span><span style="color:#c3e88d">'pending'</span><span style="color:#c792ea">)</span>
    <span style="color:#c792ea">.</span><span style="color:#c792ea">.</span><span style="color:#c792ea">.</span>
</code></span></span>

This is the same as the basic idea, Enum, but SQLAlchemy also uses the same hook property, so you can naturally modify the column value.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">order<span style="color:#c792ea">.</span>order_number <span style="color:#89ddff">=</span> <span style="color:#f78c6c">5</span>
session<span style="color:#c792ea">.</span>commit<span style="color:#c792ea">(</span><span style="color:#c792ea">)</span>
</code></span></span>

Finally, the class itself can be created at run time. It's a little niche, but thriftpy A complete module is created, which contains Thrift Defines the class of the file. In Java, you need code generation, which adds a new compilation step that may be out of sync.

All of these examples rely on Python's existing syntax, but inject new meaning into it. They don't do anything you can't do with Java or any other language, but they reduce structural duplication -- making code easier to write, easier to read, and less error prone. If you are interested in Python and want to learn more about Python and AIoT, solve testing problems, and get started guide to help you solve the puzzles encountered in learning python, we have technical experts here. If you are looking for a job, have just come out of school, or have worked, but often feel that there are many difficulties, feel that you are not proficient enough in Python, and want to continue learning. If you want to change careers, you are afraid that you won't learn, you can join us and get the latest interview materials of Python manufacturers and python crawlers, artificial intelligence and learning materials! WeChat official account [Python base] waiting for you to play Austrian.

wrap up

Python has many of the same basic concepts as Java, but it leads them in a very different direction and adds some new ideas. Java focuses on stability and reliability, while Python focuses on expressiveness and flexibility. This is a completely different way to think about imperative programming.

I doubt Python will replace Java in areas where Java excels. For example, python may not win any speed races (but see) PyPy , a JITted Python). Java has native support for threads, which the python community largely eschews. Large complex software with many dusty corners may prefer the sanity check provided by static types (but see) mypy , Python's static type checker).

But maybe Python will shine in areas where Java doesn't. A lot of software doesn't need to be particularly fast or parallel, and then other problems will surface. I find it very fast and easy to start a project in Python. Without a separate compilation step, the write / run cycle is much faster. The code is shorter, which usually means easier to understand. It's cheaper to try different architectural methods. Sometimes it's fun to try some stupid ideas, such as Implementation of goto with library.

I hope you can try Python. I had a good time. I think you will, too. Just try not to treat it as Java. All types are hidden from you.

At worst, there is always Pyjnius , it allows you to do this.

<span style="background-color:#292d3e"><span style="color:#bfc7d5"><code class="language-python">from jnius import autoclass

System <span style="color:#89ddff">=</span> autoclass<span style="color:#c792ea">(</span><span style="color:#c3e88d">'java.lang.System'</span><span style="color:#c792ea">)</span>
System<span style="color:#c792ea">.</span>out<span style="color:#c792ea">.</span>println<span style="color:#c792ea">(</span><span style="color:#c3e88d">'Hello, world!'</span><span style="color:#c792ea">)</span></code></span></span>

Keywords: Python Java

Added by broc7 on Sat, 15 Jan 2022 16:49:52 +0200