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: import
statements, from ... import ...
and __import__
functions. The first two are more common.
In use import
, it should pay attention to:
- Priority use
import A
orimport 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 ++i
be interpreted as +(+i)
, where +
denotes a positive number of symbols. For --i
is similar.
Therefore, we must understand ++i
grammatically level Python is legal, but not the increment operator in the usual sense.
Use with
automatic 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 else
clause simplified loop (Exception Processing)
In the cycle, the else
clause provides for implied whether by the cycle break
caused 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) else
clause will be executed once, and when the cycle is break
interrupt sentence, else
clause can not be executed.
And for
statements similar while
statement else
clause semantics is the same: else
the 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
, finally
they 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
try
placed 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
except
statement handle all exceptions, it is best to locate specific exception . Also not recommended to useexcept Exception
orexcept StandardError
to catch exceptions. If you must use, it is best to use theraise
statement 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
except
throw statement, the parent class in subsequent exceptionexcept
statement thrown. The reason for this is that whentry
a block has exception occurs, according to the interpreterexcept
to 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.
- 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
- 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 try
whether an exception is thrown statement, finally
the statement is always executed. Because of this feature, finally
statements are often used to do some clean-up work.
But the use of finally
time, should be especially careful trap.
- When
try
an exception occurs in the block, ifexcept
not find a corresponding exception handling statement, an exception will be temporarily stored up, whenfinally
the time is finished, the temporary preservation exception will be thrown again, but if thefinally
statement is generated a new exception or the executionreturn
orbreak
statement, then temporarily saved exceptions will be lost, resulting in abnormal shield. - In a real application development process, it is not recommended
finally
to use thereturn
statement 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 integer0
orFalse
time.
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 variablelist1
is 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 .format
rather than in%
Recommended to make use of format
the way instead %
operator to string format, reasons:
-
format
Embodiment than in the use of%
the operator more flexible. Usedformat
when mode, and the order is not necessarily identical formatting parameters -
format
The method can be easily passed as a parameterweather = [("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 None
as 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, **kwargs
for 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
*args
and**kwargs
to 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, andprint
then callstr()
the function -
repr()
The return value can generallyeval()
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 usedeval()
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]