This article mainly introduces and shares how to write efficient and elegant Python code. Friends who need it can refer to it.
This article is partially extracted from the book: "Effective Python" & "Python3 Cookbook", but it also Modifications have been made and the author's own understanding and application of best practices have been added.
The full text is about 9956 words, and it may take 24 minutes to read.
Pythonic list cutting
list[start:end:step]
If you start cutting from the beginning of the list, then ignore 0 in the start bit, for example list[:4]
If you cut all the way to the end of the list, ignore the 0 in the end bit, for example list[3:]
When cutting the list, there will be no problem even if the start or end index crosses the boundary.
List slicing will not change the original list. When the indexes are all left empty, a copy of the original list will be generated
List comprehension
Use list comprehension insteadmap
and filter
Do not use list comprehensions with more than two expressions
When there is a lot of data, list comprehensions may consume a lot of memory. In this case, it is recommended to use generator expressions
iteration
Use it when you need to get the index enumerate
##enumerate can accept the second parameter as the value added to
index during iteration
zip to traverse two iterators simultaneously
Return a tuple when traversing
About the
for and while
else
blocks after the loop The loop
The code in else will be called later. If you break out of the loop by
, else
# will not be executed. ##When the sequence to be traversed is empty, execute it immediately
else
Reverse iteration
For ordinary sequences (lists) , we can perform reverse iteration through the built-inreversed()
function:In addition, we can also implement in the class __reversed__
method, reverse iteration of the class:try/except/else/finally
if## If no exception occurs within #try
, the code
else
that is called within else
will run
finally ##It will eventually be executed
finally, where you can perform cleanup work
The decorator is used to modify the function code without changing the original function code function exists. A common scenario is to add a debugging sentence, or add
log
Besides , you can also write a decorator that receives parameters. In fact, a function is nested in the outer layer of the original decorator:
But use the decorator as above There is a problem:
That is to say, the original function has been replaced by the
new_funfunction in the decorator. Calling a decorated function is equivalent to calling a new function. When viewing the parameters, comments, and even function names of the original function, you can only see information related to the decorator. In order to solve this problem, we can use
Python's ownfunctools.wraps method.
functools.wraps is a very hack method. It can be used as a decorator on the function that will be returned inside the decorator. In other words, it is a decorator of decorators, and takes the original function as a parameter. Its function is to retain various information of the original function, so that when we view the information of the decorated original function later, it can remain exactly the same as the original function.
<p>In addition, sometimes our decorator may do more than one thing, in which case the event should be separated as an additional function. But because it may only be related to the decorator, a decorator class can be constructed at this time. The principle is very simple. The main thing is to write the <code>__call__
method in the class so that the class can be called like a function.
Use generators
Consider using generators to rewrite functions that directly return lists
There are several small problems with this method:
Every time a result that meets the conditions is obtained, the append
method must be called. But in fact our focus is not on this method at all, it is just a means for us to achieve our goal. In fact, we only need index
The returnedresult
is fine Continue to optimize
The data is stored inresult
. If the amount of data is large, it will occupy more memory
Therefore, using the generatorgenerator
will better. A generator is a function that uses a yield
expression. When the generator is called, it will not actually execute. Instead, it will return an iterator, and each time the built-in next## is called on the iterator. #function, the iterator will advance the generator to the next
yieldexpression:
list method
define an iterable container class:
In this case, how many times will the instance of the class be iterated No problem: But it should be noted that it is only an iterator that implements the__iter__ method, which can only be passed
for Loop to iterate; if you want to iterate through the
next method, you need to use the
iter method:
Sometimes, the number of parameters received by a method may not be certain. For example, when defining a summation method, it must receive at least two parameters: For this kind of receiving parameters For functions whose number is not certain and does not care about the order in which the parameters are passed in, positional parameters
*args should be used:
args are passed to the function, they need to be converted into tuples
tuple first. This means that if you pass a generator as a parameter to a function, the generator will be traversed first and converted into a tuple. This can consume a lot of memory:
Define functions that can only use keyword parameters
In the ordinary way, when calling The use of keyword parameters will not be forced when Use the method of forcing keyword parameters inPython3
Using the method of forcing keyword parameters inPython2
About the default value of the parameterIt is a cliché:The default value of a function will only be set once when the program loads the module and reads the definition of the function
That is, if a dynamic value is assigned to a parameter (For example[] or
{}), if other parameters are assigned to the parameters when calling the function later, when the function is called again in the future, the previously defined default value will be used. will change to the value assigned during the last call:
Therefore, it is more recommended to use None
as the default parameter and assign the value after judgment within the function:
Class__slots__
By default, Python uses a dictionary to save the instance attributes of an object. This allows us to dynamically add new attributes to class instances at runtime:
However, this dictionary wastes extra space - many times we will not create it So many attributes. Therefore, __slots__
can tell Python
not to use a dictionary but a fixed collection to allocate space.
__call__
By defining the __call__
method in a class, instances of the class can be made like Called like a normal function.
The advantage of implementing this method is that the state can be saved through the properties of the class without having to create a closure or global variable.
@classmethod
& @staticmethod
##@classmethod is very similar to
@staticmethod, but Their usage scenarios are different.
self as the first parameter, which means that when called through an instance, the scope of the instance is passed into the method;
@classmethod takes
cls as the first parameter, which means passing in the scope of the class itself. Whether called through a class or an instance of a class, the first parameter passed in by default will be the class itself
@staticmethod There is no need to pass in default parameters, similar to a Ordinary functions
Date to store the year/month/day Data
Date class, which will set the
day/month/year attribute during initialization. And a
getter is set through
property. After instantiation, the stored time can be obtained through
time:
Date instance by passing in a string like
2016-11-09 without changing the existing interfaces and methods?
Date class
@classmethod to create a new format string inside the class and return the method of the instance of the class:
Date class to call the
from_string method to create an instance without invading or modifying the old instantiation method:
@classmethod, you can use the
cls parameter to get the same convenience as when calling the class externally.
@staticmethod, because it is similar to an ordinary function, can be combined with The helper
@staticmethod, and then this method is called directly through the class.
@staticmethod method in the
Date class, you can use the class to Call these methods:
with statement often appears together with the context manager. Classic scenarios include:
Through the with
statement, the code completes the file opening operation and automatically closes the file when the call ends or an exception occurs during reading, that is, the file reading and writing is completed. subsequent processing work. If you don't pass the context manager, the code will be like this:
Isn't it complicated? So the advantage of using the context manager is that it automatically helps us handle the work when the code block starts and finishes executing by calling our preset callbacks. Through the __enter__
and __exit__
methods of the custom class, we can customize a context manager.
Then it can be called like this:
##When calling: Thewith statement first temporarily stores the
__exit__ method
of the
ReadFile
__enter__ of the ReadFile
class. Method
__enter__ method opens the file and returns the result to the
with statement
file_read Parameters
file_read parameters within the
with statement and read each line
statement calls the __exit__
method temporarily stored before the
method closes the file It should be noted that in ## In the #__exit__
True, so the error will not be thrown by the
with statement. Otherwise the
with statement will throw a corresponding error.
The above is the detailed content of How to write efficient Python code. For more information, please follow other related articles on the PHP Chinese website!