How to write more Python-style code

We all like Python because it makes programming and understanding easier. But if we are not careful, we will ignore the rules and write a bunch of garbage code in a non-Pythonic way, thus wasting the elegance that the excellent language of Python gives us. Python coding style is very elegant, clear and simple, the implementation of the Python interpreter import thisyou can see the preparation of Tim Peters Python Zen:

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Here I found the best Chinese version currently:

Beauty is better than ugly

Explicit is better than implicit

Simple is better than complex

Complicated is better than complicated

Flat is better than nested

Sparse is better than crowded

Readability is important

Although the code is more important than cleanliness,

The special cases we think are often not so special that the above rules must be broken

Don’t ignore exceptions for no reason unless you are silent on purpose

If you encounter ambiguous logic, please don't make a clever guess.

It should provide one, and preferably only one, a clear solution

Of course this cannot be done overnight, unless you are Dutch[1]

Of course, it is better to start immediately than never to do it.

However, never doing it is better than not thinking carefully and doing it recklessly.

If your implementation is difficult to explain, it must not be a good idea

Even if your implementation is simple enough, it might be a good way

Namespace Dafa is good, if you don't do it, you are not a human being!

[1]: The author of this article, Tim peters, explained that the Dutch here refers to Guido van Rossum, the author of Python.

Here are 8 ways to write better code in Python:

1. Forget about C-like language style

If you need to print all the elements in the list and their indices, the first thing you think of is:

for i in range(len(arr)):
    print(i, arr[i])

Then you are still writing C code. To get rid of this, keep in mind the Python keyword enumerate. It indexes all elements in the list/string and supports setting the starting number of the index :

>>> for index, item in enumerate(['a','b','c']): 
...     print(index, item)
... 
0 a
1 b
2 c
>>> for index, item in enumerate(['a','b','c'],1): #这里第二个参数可以设置起始编号
...     print(index,item)
... 
1 a
2 b
3 c

Now it looks better and more Pythonic. What about converting the list into a string? If you write:

# The C way
string = ''
for i in arr:
    string += i

It is C style. If you use the Python keyword join, it is not only more efficient, but also more elegant:

# The Python way
string = ''.join(arr)

Just like join, Python has many magical keywords, so please don't work for the language, but use that language to work for you.

Two, keep in mind PEP8

I am not asking you to follow PEP8 completely, but to follow most of the rules. What's more, there are many automatic formatting tools that are enough to make your code more beautiful. Our father of Python also said: read the code more frequently Much higher than the frequency of writing code, he is so correct! Therefore, the readability of the code is very important.

Are you curious about the code you have written? Why do you write this, why is this sentence here? Well, PEP8 is the answer to most of these questions. Although code comments are a good way, the style of the code also needs to be adjusted, such as variables i, j, count, etc. Even if you write comments when they first appear, there is no guarantee that you will remember them later, which is a waste of precious time.

Any ordinary programmer can write code that the computer can understand. Only good programmers can write code that humans can understand.

CamelCase is preferred as the class, UPPER_WITH_UNDERSCORES as the constant, and lower_with_underscores as the variable, method and module name. Even if you use it, avoid using single-name function lambda.

Three, make good use of deduction

Commonly used deductions are: list deduction, set deduction, and dictionary deduction. Let me talk about the following list comprehension.

The list comprehension is the syntax format used when we need to create a new list based on an existing list. The list comprehension includes the following four parts:

1. An input sequence (Input Sequence) 2. A variable representing a member of the input sequence (Variable) 3. An optional predicate expression that expresses the condition that the variable satisfies (Optional Predicate) 4. An output sequence, Generate an output sequence based on 2 and 3 (Output Expression)

For example, if you have a list with both numbers and characters, you need to calculate the square of the number and put the result in a new list. If you don't need a list comprehension, the code written is like this:

# bad code
a_list = [1, ‘4’, 9, ‘a’, 0, 4]

squared_ints = []
for item in a_list:
    if type(item) == types.IntType:
        squared_ints.append(item**2)

If you use the list comprehension, you only need two lines of code, which is very elegant:

a_list = [1, ‘4’, 9, ‘a’, 0, 4]
squared_ints = [ e**2 for e in a_list if type(e) == types.IntType ]

Of course, if you like map and filter, you can still do this, which was not recommended at the time because of poor readability:

map(lambda e: e**2, filter(lambda e: type(e) == types.IntType, a_list))

For example, the use of set comprehensions:

Given input

names = [ 'Bob', 'JOHN', 'alice', 'bob', 'ALICE', 'J', 'Bob' ]

hope to get:

{ 'Bob', 'John', 'Alice' }

Then the set comprehension is:

{ name[0].upper() + name[1:].lower() for name in names if len(name) > 1 }

Another example is the dictionary deduction:

mcase = {'a':10, 'b': 34, 'A': 7, 'Z':3}

mcase_frequency = { k.lower() : mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys() }

# mcase_frequency == {'a': 17, 'z': 3, 'b': 34}

It can be seen from the above. The deductive style code is elegant and human readable.

4. Are you still closing the file explicitly?

If you are still explicitly closing the file while writing the code, like the programmer in the picture above, you are working for a programming language, if you learn to use the with context manager, then you are a Python programmer, let the programming language be You work:

with open('filename.txt', 'w') as filename:
    filename.write('Hello')

When the program exits the with block, the file is automatically closed. The syntax format of the with statement:

with VAR as EXPR:
    BLOCK

Is equivalent to:

mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)

There are many network connections and database connection libraries that provide the with function. Even after being familiar with the implementation mechanism of with, you can implement the with function yourself:

class File(object):
    def __init__(self, file_name, method):
        self.file_obj = open(file_name, method)
    def __enter__(self):
        return self.file_obj
    def __exit__(self, type, value, traceback):
        self.file_obj.close()

Once you have defined __enter__, __exit__methods can be used with the statement:

with File('demo.txt', 'w') as opened_file:
    opened_file.write('Hola!')

Five, use iterators and generators

Iterator: iterator Generator: generator

Both iterators and generators are powerful tools in Python that deserve to be mastered. An iterator is a more general concept: any object is an iterator as long as the class it belongs to has a __next__method (next in Python 2) and a __iter__method that returns self .

Every generator is an iterator, but not vice versa. The generator is constructed by calling a function with one or more yield expressions, and the function is an object that satisfies the definition of iterator in the previous paragraph.

Use difference:

Many technical bloggers on the Internet say that generators are lazy versions of iterators, which save more memory than iterators. It is actually wrong. They all save memory (I will give an example).

The real difference between them is: when you need a class with some complex state maintenance behavior, or want to expose methods other than __next__(and __iter__and __init__), you need a custom iterator, not a generator.

Usually, a generator (sometimes, for simple enough requirements, a generator expression) is sufficient, and it is easier to write code.

For example, to calculate the direct square of a positive integer from a to b (b is much greater than a), the generator would be:

def squares(start, stop):
    for i in range(start, stop):
        yield i * i

generator = squares(a, b)

or:

generator = (i*i for i in range(a, b))

If it is an iterator, it is like this:

class Squares(object):
    def __init__(self, start, stop):
       self.start = start
       self.stop = stop
    def __iter__(self): return self
    def __next__(self): # next in Python 2
       if self.start >= self.stop:
           raise StopIteration
       current = self.start * self.start
       self.start += 1
       return current

iterator = Squares(a, b)

It can be seen that iterators are a little troublesome to write, and when they are more flexible, for example, when you want to provide a current method, you can directly add it to the Squares class:

    def current(self):
       return self.start

It can be seen from the above that the iterator does not save all the values ​​between a and b, and all of them do not consume too much memory. This can also be tested by yourself. The code is as follows:

>>> from collections.abc import Iterator
>>> from sys import getsizeof
>>> a = [i for i in range(1001)]
>>> print(type(a))
<class 'list'>
>>> print(getsizeof(a))
9016
>>>
>>> b = iter(a)
>>> print(type(b))
<class 'list_iterator'>
>>> print(isinstance(b,Iterator))
True
>>> print(getsizeof(b))
48
>>> c = (i for i in range(1001))
>>> print(getsizeof(b))
48
>>> type(c)
<class 'generator'>
>>> type(b)
<class 'list_iterator'>

It can be seen that b is iterator and c is generator, and they occupy the same memory size.

Six, make good use of itertools

The itertools module standardizes a core tool set for fast and efficient use of memory. These tools are useful by themselves or in combination. Together they form "iterator algebra", which makes it possible to create concise and efficient special tools in pure Python. For example, if you want all combinations of characters in a string or all combinations of numbers in a list, you only need to write

from itertools import combinations
names = 'ABC'
for combination in combinations(names, 2):
    print(combination)
''' Output -
    ('A', 'B')
    ('A', 'C')
    ('B', 'C')
'''

This is a standard library that is worth using frequently. For more detailed functions, please refer to the official document: https://docs.python.org/zh-cn/3/library/itertools.html [1]

Seven, make good use of collections

This is another standard library collection that is worth using. It provides multiple containers that replace the built-in data types, such as defaultdict, OrderedDict, namedtuple, Counter, deque, etc., which are very useful and much safer and more stable than their own implementation. such as:

# frequency of all characters in a string in sorted order
from collections import (OrderedDict, Counter)
string = 'abcbcaaba'
freq = Counter(string)
freq_sorted = OrderedDict(freq.most_common())
for key, val in freq_sorted.items():
    print(key, val)
''' Output -
    ('a', 4)
    ('b', 3)
    ('c', 2)
'''

Not much to say, see the official document: https://docs.python.org/3/library/collections.html [2]

8. Don't overuse classes

Don't overuse classes. Programmers who insist on using Java and C++ will often use classes, but when using Python, they can reuse code with the help of functions and modules. Unless absolutely necessary, there is no need to create a class.

This article describes 8 methods for you to write better Python code, I hope it will help you.

Recommended reading:

10 tips to make your code more elegant

6 Python codes worth playing

Reference

[1]

https://docs.python.org/zh-cn/3/library/itertools.html: https://docs.python.org/zh-cn/3/library/itertools.html

[2]

https://docs.python.org/3/library/collections.html: https://docs.python.org/3/library/collections.html

Guess you like

Origin blog.csdn.net/somenzz/article/details/109685295