12月 1, 2023

Manufacturing

Processing Machinery

Detailed explanation of python decorators

2 min read

1. The official definition of the decorator

A decorator is essentially a Python function (actually a closure), which allows other functions to add additional functions without any code changes. The return value of the decorator is also a function object. Decorators are used in the following scenarios, such as: inserting logs, performance testing, transaction processing, caching, permission verification and other scenarios.

Second, add a decorator to a function

1. General writing

# 为函数添加一个统计运行时长的功能
import time

def how_much_time(func):
def inner():
t_start = time.time()
func()
t_end = time.time()
print(“一共花费了{0}秒时间”.format(t_end – t_start, ))
return inner
# 将增加的新功能代码以及被装饰函数运行代码func()一同打包返回,返回的是一个内部函数,这个被返回的函数就是装饰器

def sleep_5s():
time.sleep(5)
print(“%d秒结束了” % (5,))

def sleep_6s():
time.sleep(6)
print(“%d秒结束了” % (6,))

sleep_5s = how_much_time(sleep_5s)
# 因为sleep_5s函数的功能就是睡5秒钟,虽然增加了统计运行时间的功能,但是他本身功能没变(还是睡5秒钟),所以仍然用原来函数名接收增加功能了的自己
sleep_6s = how_much_time(sleep_6s)

t1 = threading.Thread(target=sleep_5s)
t2 = threading.Thread(target=sleep_6s)
t1.start()
t2.start()
# 5秒结束了
# 一共花费了5.014161109924316秒时间
# 6秒结束了
# 一共花费了6.011810302734375秒时间

2. Standard grammatical sugar writing

Here is an example of adding two decorators.

2.1 Add two decorators to a function

# 为函数添加一个统计运行时长的功能以及日志记录功能
import time
import threading

def how_much_time(func):
print(“how_much_time函数开始了”)
def inner():
t_start = time.time()
func()
t_end = time.time()
print(“一共花费了{0}秒时间”.format(t_end – t_start, ))
return inner

def mylog(func):
print(“mylog函数开始了”)
def inner_1():
print(“start”)
func()
print(“end”)
return inner_1

@mylog
@how_much_time
# 等价于mylog(how_much_time(sleep_5s))
def sleep_5s():
time.sleep(5)
print(“%d秒结束了” % (5,))

if __name__ == ‘__main__’:
sleep_5s()
#how_much_time函数开始了
#mylog函数开始了
#start
#5秒结束了
#一共花费了5.012601613998413秒时间
#end

2.2 Execution order when a function has two decorators

3. Typical writing method with parameter decorator

Fourth, @wraps() syntax sugar (understand)
Because the decorator is essentially a function, a modified function, it is two different function objects from the original undecorated function.

Therefore, this decorator loses some attributes of the original function object, such as: __name__, __doc__ and other attributes. These properties can be preserved using wraps syntactic sugar.

Five, class decorator
The main idea of writing a class decorator is to return a function object with new functions added, but this function object is an instance object of a class. Since the decorator is a callable object, the __call__ method must be implemented in the class, so that various instances generated by the class can be run by adding ().

1. Class decorator without parameters

import time

class Decorator:
def __init__(self, func):
self.func = func

def defer_time(self):
time.sleep(5)
print(“延时结束了”)

def __call__(self, *args, **kwargs):
self.defer_time()
self.func()

@Decorator
def f1():
print(“延时之后我才开始执行”)

f1()

2. Class decorator with parameters

import time

class Decorator:
def __init__(self, func):
self.func = func

def defer_time(self,time_sec):
time.sleep(time_sec)
print(f”{time_sec}s延时结束了”)

def __call__(self, time):
self.defer_time(time)
self.func()

@Decorator
def f1():
print(“延时之后我才开始执行”)

f1(5)