Home  >  Article  >  Backend Development  >  Detailed explanation of python decorators

Detailed explanation of python decorators

藏色散人
藏色散人Original
2020-02-13 11:41:204941browse

Detailed explanation of python decorators

Detailed analysis of python decorator

Detailed analysis of python decorator

What Is it a decorator?

Recommended learning: Python video tutorial

Python decorators (fuctional decorators) are functions used to expand the functionality of the original function. The purpose is to When changing the original function name (or class name), add new functions to the function.

The special thing about this function is that its return value is also a function. This function is a function with the "original" function embedded in it.

Generally speaking, if we want to expand the original function code, the most direct way is to invade the code and modify it, for example:

import time
def f():
    print("hello")
    time.sleep(1)
    print("world")  

This is our most original function, and then we try to record the total execution time of this function, then The simplest way is to change the original code:

import time
def f():
    start_time = time.time()
    print("hello")
    time.sleep(1)
    print("world")
    end_time = time.time()
    execution_time = (end_time - start_time)*1000
    print("time is %d ms" %execution_time)

But in actual work, sometimes the core code cannot be changed directly, so without changing the original code, we You can define another function. (But the function needs to be executed again to take effect)

import time
def deco(func):
    start_time = time.time()
    f()
    end_time = time.time()
    execution_time = (end_time - start_time)*1000
    print("time is %d ms" %execution_time)
def f():
    print("hello")
    time.sleep(1)
    print("world")
if __name__ == '__main__':
    deco(f)
    print("f.__name__ is",f.__name__)
    print()

Here we define a function deco, whose parameter is a function, and then embed the timing function into this function . But if you want to expand the functions of these tens of millions of functions,

means executing the deco() function ten million times, so this is not ideal! Next, we can try to use decorators to achieve it. First Take a look at the most original appearance of the decorator.

import time
def deco(f):
    def wrapper():
        start_time = time.time()
        f()
        end_time = time.time()
        execution_time = (end_time - start_time)*1000
        print("time is %d ms" %execution_time )
    return wrapper
@deco
def f():
    print("hello")
    time.sleep(1)
    print("world")
if __name__ == '__main__':
    f()

The deco function here is the most original decorator. Its parameter is a function, and the return value is also a function.

The function f() as a parameter is executed inside the return function wrapper(). Then add @deco in front of the function f(),

f() function is equivalent to being injected With the timing function, now as long as f() is called, it has been transformed into a "new function with more functions",

(no need to repeat the original function).

Extension 1: Decorator with fixed parameters

import time
def deco(f):
    def wrapper(a,b):
        start_time = time.time()
        f(a,b)
        end_time = time.time()
        execution_time = (end_time - start_time)*1000
        print("time is %d ms" % execution_time)
    return wrapper
@deco
def f(a,b):
    print("be on")
    time.sleep(1)
    print("result is %d" %(a+b))
if __name__ == '__main__':
    f(3,4)

Extension 2: Decorator without fixed parameters

import time
def deco(f):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        f(*args, **kwargs)
        end_time = time.time()
        execution_time_ = (end_time - start_time)*1000
        print("time is %d ms" %execution_time)
    return wrapper
@deco
def f(a,b):
    print("be on")
    time.sleep(1)
    print("result is %d" %(a+b))
@deco
def f2(a,b,c):
    print("be on")
    time.sleep(1)
    print("result is %d" %(a+b+c))
if __name__ == '__main__':
    f2(3,4,5)
    f(3,4)

Extension 3: Use multiple decorators to decorate a function

import time
def deco01(f):
    def wrapper(*args, **kwargs):
        print("this is deco01")
        start_time = time.time()
        f(*args, **kwargs)
        end_time = time.time()
        execution_time = (end_time - start_time)*1000
        print("time is %d ms" % execution_time)
        print("deco01 end here")
    return wrapper
def deco02(f):
    def wrapper(*args, **kwargs):
        print("this is deco02")
        f(*args, **kwargs)
        print("deco02 end here")
    return wrapper
@deco01
@deco02
def f(a,b):
    print("be on")
    time.sleep(1)
    print("result is %d" %(a+b))
if __name__ == '__main__':
    f(3,4)
'''
this is deco01
this is deco02
hello,here is a func for add :
result is 7
deco02 end here
time is 1003 ms
deco01 end here
'''

Decorator calling order

Decorators can be used superimposed, so what is the order of the code after using the decorator?

For the "@" syntax in Python Sugar, the order in which the decorators are called is the reverse of the order declared using the @ syntax sugar.

In this example, "f(3, 4) = deco01(deco02(f(3, 4)))".

Python built-in decorators

There are three built-in decorators in Python, all related to classes: staticmethod, classmethod and property .

staticmethod is a class static method. Its difference from the member method is that it has no self parameter and can be called without instantiating the class.

The difference between classmethod and member method is that The first parameter received is not self (a pointer to a class instance), but cls (the specific type of the current class)

property means property, indicating information that can be directly accessed through a class instance

I won’t introduce staticmethod and classmethod here. Let’s take a look at property through an example.

Detailed explanation of python decorators

Note that for Python new-style classes, if the member function decorated by the "@var.setter" decorator above is removed, Foo. The var attribute is a read-only attribute, and an exception will be thrown when assigning a value using "foo.var = 'var 2′". However, for Python classic class, the declared attributes are not read-only, so even if the "@var.setter" decorator is removed, no error will be reported.

Summary

This article introduces some uses of Python decorators. The code of the decorator is relatively easy to understand. It is easy to understand as long as you practice it through some examples.

The above is the detailed content of Detailed explanation of python decorators. 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