Writing high-quality Python programs (3) Basic syntax

This series of articles is a summary of the essence of "Writing high-quality code-91 suggestions for improving Python programs".

About importing modules

3 ways of introducing external module Python: importstatements, from ... import ...and __import__functions. The first two are more common.

In use import, it should pay attention to:

  • Priority use import Aorimport A as a
  • Use sparingly from A import B
  • Try to avoid using from A import *

For from a import ..., if uncontrolled use, it will bring problems:

  • Namespace conflicts
  • The problem of nested loop import (two files import each other's variables or functions or classes)

i += 1 not equal to ++i

Python interpreter will ++ibe interpreted as +(+i), where +denotes a positive number of symbols. For --iis similar.

Therefore, we must understand ++igrammatically level Python is legal, but not the increment operator in the usual sense.

Use withautomatic shut resources

After the file operation is completed, you should close them immediately, because the opened file will not only occupy system resources, but also may affect the operation of other programs or processes, and may even cause the user's expectations to be inconsistent with the actual operation results.

Python provides a with statement with the syntax:

with 表达式 [as 目标]:
    代码块

The with statement supports nesting, supports multiple with clauses, and they can be converted to each other. with expr1 as e1, expr2 as e2 Equivalent to the following nested form:

with expr1 as e1:
    with expr2 as e2:

Use elseclause simplified loop (Exception Processing)

In the cycle, the elseclause provides for implied whether by the cycle breakcaused by the end of the cycle judgment statement. example:

# 以下两段代码等价
# 借助了一个标志量 found 来判断循环结束是不是由 break 语句引起的。
def print_prime(n):
    for i in range(2, n):
        found = True
        for j in range(2, i):
            if i % j == 0:
                found = False
                break
        if found:
            print("{} is a prime number".format(i))

def print_prime2(n):
    for i in range(2, n):
        for j in range(2, i):
            if i % j == 0:
                break
        else:
            print("{} is a prime number".format(i))

When the cycle "natural" end (the loop condition is false) elseclause will be executed once, and when the cycle is breakinterrupt sentence, elseclause can not be executed.

And forstatements similar whilestatement elseclause semantics is the same: elsethe block is executed at the end of a normal cycle and cycle conditions are not met.

Follow some basic principles of exception handling

Python commonly used in exception handling syntax try, , except, else, finallythey can have various combinations. The syntax is as follows:

# Run this main action first
try:
    <statements>

# 当 try 中发生 name1 的异常时,进行处理
except <name1>:
    <statements>

# 当 try 中发生 name2 或 name3 中的某一个异常时
except (name2, name3):
    <statements>

# 当 try 中发生 name4 的异常时处理,并获取对应实例
except <name4> as <data>:
    <statements>

# 其他异常时,进行处理
except:
    <statements>

# 没有异常时,执行
else:
    <statements>

# 无论有没有异常,都执行
finally:
    <statements>

Exception handling usually requires following basic principles:

  • Not recommended tryplaced too much code . The problem caused by putting too much code in the try is that if an exception is thrown in the program, it will be more difficult to locate and cause inconvenience to debugging and repair, so try to put it only in front of the statement block that may throw an exception try statement.
  • Prudent use a separate exceptstatement handle all exceptions, it is best to locate specific exception . Also not recommended to use except Exceptionor except StandardErrorto catch exceptions. If you must use, it is best to use the raisestatement to throw an exception passed to the upper layer.
  • Pay attention to the order of exception catching and handle exceptions at the appropriate level.
    • Users can also inherit from built-in exceptions to build their own exception classes, thereby extending the inheritance structure of built-in classes. The order in which exceptions are captured is very important in this case. To more precisely locate the cause of the error, the recommended approach is to inherit Neutron anomalies in the preceding exceptthrow statement, the parent class in subsequent exception exceptstatement thrown. The reason for this is that when trya block has exception occurs, according to the interpreter exceptto match the order of declaration in the first match facilitate immediately handle the exception.
    • The order in which exceptions are caught is very important. At the same time, exceptions should be handled at an appropriate location. One principle is that if an exception can be handled at the location where it is caught, it should be handled in a timely manner. When passing to the upper layer, you need to be alert to the situation where the abnormality is lost. You can use raise without parameters to pass.
  • Use more friendly exception information and follow the specifications of exception parameters. Generally speaking, there are two types of abnormal readers: those who use software and those who develop software.

Avoid possible traps in finally

Regardless of trywhether an exception is thrown statement, finallythe statement is always executed. Because of this feature, finallystatements are often used to do some clean-up work.
But the use of finallytime, should be especially careful trap.

  • When tryan exception occurs in the block, if exceptnot find a corresponding exception handling statement, an exception will be temporarily stored up, when finallythe time is finished, the temporary preservation exception will be thrown again, but if the finallystatement is generated a new exception or the execution returnor breakstatement, then temporarily saved exceptions will be lost, resulting in abnormal shield.
  • In a real application development process, it is not recommended finallyto use the returnstatement to return, this approach will not only bring misunderstanding and may lead to very serious mistake.

Understand None in depth and correctly judge whether the object is empty

The following data in Python will be treated as empty:

  • constant None
  • constant False
  • Any form of zero-value type, such as 0, 0L, 0.0,0j
  • Empty sequence, such as '', (),[]
  • Empty dictionary, such as {}
  • When the user-defined classes are defined __nonzero__()and __len__()methods, and the method returns an integer 0or Falsetime.
if list1 # value is not empty
    Do something
else: # value is empty
    Do some other thing
  • It calls internal methods during execution __nonzero__()to determine the variable list1is null and returns the result.

Note: __nonzero__()Method-This internal method is used to test the null value of its own object, and returns 0/1 or True / False.

  • If an object does not define the method, Python obtain the __len__()results of the method invocation is to be judged. __len__()A return value of 0 means empty. If a class does not define __len__()the method does not define __nonzero__()a method, examples of the class are used if the determination result is True.

Try to use a character string format .formatrather than in%

Recommended to make use of formatthe way instead %operator to string format, reasons:

  • formatEmbodiment than in the use of %the operator more flexible. Used formatwhen mode, and the order is not necessarily identical formatting parameters

  • format The method can be easily passed as a parameter

    weather = [("Monday", "rain"), ("Tuesday", "sunny"), ("Wednesday", "sunny"), ("Thursday", "rain"), ("Friday", "cloudy")]
    formatter = "Weather of '{0[0]}' is '{0[1]}'".format
    for item in map(formatter, weather):
        print(item)
    
  • %It will eventually be replaced by .format. According to the official Python documentation, the reason remain %the operator is to maintain backward compatibility

  • %Special care is needed when using the method in some special cases, for %direct formatting character of this form, if the character itself is a tuple, you need to use %to use (itemname,)this form in order to avoid errors, note the comma.

Treat mutable objects and immutable objects differently

Everything in Python is an object, and objects are divided into mutable objects and immutable objects according to whether their values ​​can be modified .

  • Immutable object

    • digital
    • String
    • Tuple
  • Mutable object

    • dictionary
    • List
    • Byte array

Be particularly vigilant when using mutable objects as the default parameters of a function . Changes to mutable objects will directly affect the original objects.

The best way is passed Noneas the default parameters, dynamically generated mutable objects when creating objects.

  • For a variable object, the slicing operation is equivalent to a shallow copy.

  • For immutable objects, when we perform related operations on it, Python actually still retains the original value and re-creates a new object , so string objects are not allowed to be assigned by index. When pointing to a string object, operations on one of the objects will not affect the other object.

Function passing parameters is neither by value nor by reference

The method of passing parameters to functions in Python is neither by value nor by reference .

It should be the correct name for transfer objects (call by object) or a reference mass objects (call-by-object-reference ).

Function parameters pass the entire object in the process of passing,

  • For mutable objects : its modifications are visible outside and inside the function, and this object is shared between the caller and the callee
  • For immutable objects : Since they cannot be actually modified, the modification is often achieved by generating a new object and then assigning values

Use variable length parameters with caution

Use variable length parameters with caution *args, **kwargsfor the following reasons:

  • Too flexible to use. Variable-length parameters mean that the signature of this function is not clear enough, and there are many ways to call it. In addition, the variable length parameter may destroy the robustness of the program.
  • If a function parameter list is very long, although by using *argsand **kwargsto simplify the definition of the function, but usually this function can have a better implementation, it should be reconstructed. For example, tuples and dictionaries can be passed in directly.

Variable length parameters are suitable for use in the following situations:

  • Add a decorator to the function
  • If the number of parameters is uncertain, consider using variable length parameters
  • Used to implement function polymorphism, or when the subclass needs to call some methods of the parent class in the case of inheritance

In-depth understanding str()and repr()distinction

Function str()and repr()can be converted to a string Python objects, and an output using both are very similar. There are the following differences:

  • The two goals are different:

    • str() Mainly for users, its purpose is readability, the return form is a string type with strong user-friendliness and readability
    • And repr()for developers, the purpose of accuracy, the return value showing the meaning of the interior of the Python interpreter, used for debug
  • The default is called when input directly in the interpreter repr()function, and printthen call str()the function

  • repr()The return value can generally eval()function to restore the object. There are usually the following equations:obj == eval(repr(obj))

  • Generally, the class should be defined __repr__()method, and __str__()the method are optional, as readability is more important than accuracy should be considered when defined __str__()method. If the class is not defined __str__()method, using default __repr__()result of the process to return the string representation of the object. Users to achieve __repr__()time method, it is preferable to ensure that the return value can be used eval()a method that the object is again restored.

Distinguish the applicable scenarios of static methods and class methods

Static method:

class C(object):
    @staticmethod
    def f(arg1, arg2, ...):

Class methods:

class C(object):
    @classmethod
    def f(cls, arg1, arg2, ...):

Both can be accessed via 类名.方法名or 实例.方法名.

Among them, the static method does not have the special behavior of the conventional method, such as binding, unbinding, implicit parameters and other rules, and the call of the class method uses the class itself as its implicit parameter, but the call itself does not need to explicitly provide the parameter.

Class method

  • There is no explicit declaration of cls when calling, but in fact the class itself is passed in as a hidden parameter
  • Class methods can determine whether they are called through a base class or through a subclass
  • When a class method is called by a subclass, it can return the attributes of the subclass instead of the base class
  • When a class method is called by a subclass, you can call other class methods of the subclass

Static method

  • Neither related to a specific instance nor to a specific class
  • The reason that static methods are defined in the class is that they can organize the code more effectively, so that the vertical distance of the related code is closer, and the maintainability of the code is improved.

The article was first published on the public account [The Road to Python and Algorithms]

Guess you like

Origin www.cnblogs.com/monteyang/p/12728729.html