程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Decorator for Python

編輯:Python

First look at this @wrap grammar , confused , Let's analyze it carefully

One 、 background

Let's take a look at the following example , There is a summation function add, Now ask to count the length of time the function is executed

def add(a, b):
print(a+b)

It's easier to think of

import time
def add(a, b):
start = time.time() # Starting time
print(a + b)
time.sleep(4) # Simulation time operation
long = time.time() - start # Calculate the time interval
print(f' Total time consuming {long} second ')

By doing so, you can achieve the requirements , But the original function has been modified , It not only increases the coupling , Extension and reuse also become difficult to achieve .

If you add another function of logging , And time length statistics of all functions in the program , Think about it .

  therefore , We put add As a parameter , You can write like this :

import time
def timer(func,*args):
start = time.time()
func(*args)
time.sleep(4) # Simulation time operation
long = time.time() - start
print(f' Total time consuming {long} second ')
timer(add,1,2)

  That doesn't change the original function, does it ? Yes , But it changed the way function calls , Every call add All of them need to be modified , Doing so just passes on the contradiction .

also The original function cannot be modified , also You can't change the calling method , So what should we do ? It's time for the decorator to appear .

Two 、 Decorator

Without changing the original function code , Add extra features . Take an example

import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs) # Get the decorated function here ——func, And execute the function
time.sleep(2)# Simulation time operation
long = time.time() - start
print(f' Total time consuming {long} second .')
return wrapper # Returns a reference to an inner function
@timer
def add(a, b):
print(a+b)
add(1, 2) # Normal call add

Print

 timer We transformed it into a decorator , It accepts decorated functions as input parameters , Returns a reference to an internally nested function ( Be careful : The function... Is not executed here ), Internal nested functions wrapper Hold a reference to the decorated function, that is func.

Look at the code and you'll understand it well , Decorators are similar to C++ Function pointer of ,C# Commission of . and “@” yes Python The grammar sugar of , Its function is similar to :

add = timer(add) # What's returned here is timer.<locals>.wrapper Function reference for
add(1, 2)

To sum up add Function execution flow :

Module loading --> encounter @, perform timer function , Pass in add function --> Generate timer.<locals>.wrapper Function and name it add--> call add(1, 2)--> To carry out timer.<locals>.wrapper(1, 2) --> wrapper Internally held original add Function reference (func), call func(1, 2) --> Go ahead and finish wrapper function

ask : If there are multiple decorators , What is the order of execution ? Look at the code below

import time
def test1(func):
def wrapper(*args, **kwargs):
print('before test1 ...')
func(*args, **kwargs)
print('after test1 ...')
return wrapper # Returns a reference to an inner function
def test2(func):
def wrapper(*args, **kwargs):
print('before test2 ...')
func(*args, **kwargs)
print('after test2 ...')
return wrapper # Returns a reference to an inner function
@test2
@test1
def add(a, b):
print(a+b)
add(1, 2) # Normal call add

  Print

Think of the decorator as an onion , Wrap the function layer by layer from near to far , The execution is to take a knife and cut from one side , Until the end of cutting to the other side .

3、 ... and 、 Parameter decorator

After understanding the decorator , We can think about it , How to write a decorator with parameters ? We know that the decorator ultimately returns a reference to a nested function , Just remember this , The decorator was left to us . Write a decorator with arguments :

 3.1 Don't use @wraps Decorator

import time
def auth(permission):
def _auth(func):
def wrapper(*args, **kwargs):
print(f" Verify permissions [{permission}]...")
func(*args, **kwargs)
print(" completion of enforcement ...")
return wrapper
return _auth
@auth("add")
def add(a, b):
print(a + b)
add(2,3)
print(add.__name__)
print(add.__doc__)

notes : Don't use @wraps Decorator time , have a look __name__、__doc__ What is the output  

 

  We can see , The return is wrapper Method reference , Also is to let add Yes wrapper Method , So call add.__name__, It's actually wrapper.__name__, In this way, you may get the name and comment of the embedded function of the decorator when you look up the name and comment of the method later .

3.2 Use @wraps(func)

import time
from functools import wraps
def auth(permission):
def _auth(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f" Verify permissions [{permission}]...")
func(*args, **kwargs)
print(" completion of enforcement ...")
return wrapper
return _auth
@auth("add")
def add(a, b):
print(a + b)
print(add(2,3))
print(add.__name__)
print(add.__doc__)

summary :Python Decorator (decorator) At the time of realization , The decorated function is actually another function ( Function properties such as function name will change ), In order not to affect ,Python Of functools There is a package called wraps Of decorator To eliminate such side effects . Write a decorator When , It's better to add functools Of wrap, It can keep the name of the original function and docstring.

Reference resources :

python Decorator wraps effect _hqzxsc2006 The blog of -CSDN Blog _python3 wraps

 Python Decorator depth analysis - You know


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved