Home  >  Article  >  Backend Development  >  How to write efficient Python code

How to write efficient Python code

巴扎黑
巴扎黑Original
2017-09-09 11:38:381377browse

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

Use

zip to traverse two iterators simultaneously

##zip

Return a tuple when traversing

About the

for

and while else blocks after the loop The loop

ends normally

The code in else will be called later. If you break out of the loop by

break

, else# will not be executed. ##When the sequence to be traversed is empty, execute it immediatelyelse

Reverse iteration

For ordinary sequences (lists) , we can perform reverse iteration through the built-in

reversed()

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

# before

finally ##It will eventually be executedfinally, where you can perform cleanup work

Function uses decorator

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

monitoring

to an existing function. For example:

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_fun

function 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 own

functools.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:

After obtaining a generator, you can traverse normally It:

If you still need a list, you can use the function call result as a parameter and then call the

list method

Iterable objects

It should be noted that ordinary iterators can only iterate for one round, and repeated calls after one round are invalid. The way to solve this problem is that you can

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:

Use positional parameters

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:

But it should be noted that the length is variable When the parameters

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:

Use keyword arguments

Keyword arguments improve code readability

You can pass the key Word parameters provide default values ​​​​for functions

It is convenient to expand function parameters

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 in

Python3

Using the method of forcing keyword parameters in

Python2

About the default value of the parameter

It 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.

Ordinary methods within the class all use

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

to understand their usage scenarios through examples:

Suppose we need to create a class named

Date to store the year/month/day Data

The above code creates the

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:

But what if we want to change the way properties are passed in? After all, it is annoying to have to pass in the three attributes of year/month/day during initialization. Can you find a way to create a

Date instance by passing in a string like 2016-11-09 without changing the existing interfaces and methods?

You may think of this method:

But it’s not good enough:

Write an extra method outside the class, each time You have to format it and get the parameters again

This method is only related to the

Date class

It does not solve the problem of too many parameters being passed in

This You can use

@classmethod to create a new format string inside the class and return the method of the instance of the class:

In this way, we You can use the

Date class to call the from_string method to create an instance without invading or modifying the old instantiation method:

Benefits:

In

@classmethod, you can use the cls parameter to get the same convenience as when calling the class externally.

You can go further in it Encapsulating this method to improve reusability

is more in line with object-oriented programming

And

@staticmethod, because it is similar to an ordinary function, can be combined with The helper

method related to this class is placed in the class as

@staticmethod, and then this method is called directly through the class.

After placing the date-related auxiliary class functions as the

@staticmethod method in the Date class, you can use the class to Call these methods:

Create a context manager

Context manager, the popular introduction is: before the code block is executed, preparation work is done first; After the code block is executed, do the final processing. The

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:

The

with statement first temporarily stores the __exit__ method of the ReadFile

class and then calls the

__enter__ of the ReadFile class. Method

__enter__ method opens the file and returns the result to the with statement

The result of the previous step is passed to

file_read Parameters

Operate the

file_read parameters within the with statement and read each line

After the reading is completed, ## The #with

statement calls the __exit__ method temporarily stored before the

__exit__

method closes the file It should be noted that in ## In the #__exit__

method, we close the file, but finally return

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn