Home  >  Article  >  Backend Development  >  In-depth understanding of Python decorators

In-depth understanding of Python decorators

高洛峰
高洛峰Original
2017-01-23 14:41:541054browse

Introduction to decorators:

Decorator (decorator) is an advanced Python syntax. Decorators can process a function, method or class. In Python, we have many ways to process functions and classes. For example, in Python closures, we see function objects as the return result of a certain function. Compared with other methods, the decorator syntax is simple and the code is highly readable. Therefore, decorators are widely used in Python projects.

The decorator first appeared in Python 2.5. It was originally used to process callable objects such as functions and methods (callable objects, such objects are defined with a __call__ method). In Python 2.6 and later Python versions, decorators are further used to process classes.

Decorators are mainly used to wrap functions for some commonly used functions, such as: log printing, function timing, and identity authentication. We can use decorators to achieve this, which can reduce the complexity of the entire program and reduce the amount of code in the program.

It is actually a function. The difference is that it takes a function as a parameter and then returns an alternative version of the function.

Let’s look at a simple example:

def add_number(func):
def adder(arg):
return func(arg)+100
return adder
def f(x):
return x
f=add_number(f)
print f(20)

add_number is a decorator function that accepts a function (f) as a parameter and then returns another The function (adder) is assigned to the original function, so that the original function can implement the addition function without adding additional code.

This is the original implementation of the decorator.

But, this method is still a bit inconvenient. After all, we still go around in a circle and use f=add_number(f) to reassign the original function.

In fact, the following methods can be used to simplify the reference to decorators in Python.

def add_number(func):
def adder(arg):
return func(arg)+100
return adder
@add_number
def f(x):
return x
print f(20)

It only requires a simple @add_numbe call. Isn’t it convenient? It’s much simpler and basically does not invade the original code.

Well, everyone noticed that as a decorator, there are only two parameters accepted each time: functions and function parameters, but the writing format is basically the same. Is there any way to simplify this kind of writing?

Yes, Python provides a decorator package, which can greatly simplify the writing of decorators.

So, the third implementation method is:

from decorator import decorator
@decorator
def wrapper(func,arg):
return func(arg)+100
@wrapper
def f(x):
return x
print f(20)

Oh, it is indeed simpler~

The above example is accepted All have one parameter. In fact, the function itself can accept variable parameters.

For example:

@decorator
def wrapper(f,arg1,*args,**kwargs):
print "I am just a wrapper~"
return f(arg1,*args,**kwargs)
@wrapper
def f(arg1,*args,**kwargs):
print arg1
for eacheArg in args:
print 'non-keyword arg:',eacheArg
for eachKw in kwargs.keys():
print 'keyword arg: %s:%d' % (eachKw,kwargs[eachKw])
args=('Joy','Steve')
kwargs={"age":20}
f('China',*args,**kwargs)

The output result is:

I am just a wrapper~
China
non-keyword arg: Joy
non-keyword arg: Steve
keyword arg: age:20

About the difference between *args and **kwargs , both can be used to represent variable-length arguments. It's just that the former is represented by Yuanzu and has no key value, while the latter is a dictionary with key value. Both can be used in the same function, however, *args must appear before **kwargs.

For example:

def test_var_args_call(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
args=(1,2,3)
kwargs ={"arg1":"1","arg3": 3, "arg2": "2"}
test_var_args_call(*args)
print '-----------------'
test_var_args_call(**kwargs)

The implementation effect of both is the same.

The last example is to decorate a function by displaying the execution time of the function

import time
def log(func):
def wrapper(*args, **kw):
print '[%s] %s() was called...' % (time.ctime(),func.__name__)
return func(*args, **kw)
return wrapper
@log
def foo():
pass
for i in range(4):
foo()
time.sleep(1)

The output result is as follows:

[Wed Jul 27 09:17:23 2016] foo() was called...
[Wed Jul 27 09:17:24 2016] foo() was called...
[Wed Jul 27 09:17:25 2016] foo() was called...
[Wed Jul 27 09:17:26 2016] foo() was called...

The above is the in-depth understanding of Python decorators introduced by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. I would also like to thank you all for your support of the PHP Chinese website!

For more in-depth understanding of Python decorator-related articles, please pay attention to 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