Example 1: Plain decorator
def name(n):
def func(x):
res = n(x+x)
return res
return func
@name
def run(x): # run = name(run)
print(x)
if __name__ == '__main__':
run(1)
# 2
def name(n):
def func(*x):
res = n(x+x)
return res
return func
@name
def run(x): # run = name(run)
print(x)
if __name__ == '__main__':
run(1)
# (1, 1)
For the comparison between the above two, pay attention to the parameter passing. One is an ordinary value pass, and the other is the addition of two tuples.
Example 2: Common decorator pass value
def name(n):
def func(x, y):
res = n(x,y)
return res
return func
@name
def run(x, y): # run = name(run)
print(x, y)
if __name__ == '__main__':
run(1, 2)
# 1 2
Just imagine, how to achieve 1+2, in the run function or in the name function
def name(n):
def func(x, y):
res = n(x,y)
return res
return func
@name
def run(x, y): # run = name(run)
print(x + y)
if __name__ == '__main__':
run(1, 2)
Implemented in the run function, the name function is similar to the call operation, and can also be implemented in the name function
def name(n):
def func(x, y):
res = n(x,y)
print(x + y)
return res
return func
@name
def run(x, y): # run = name(run)
# print(x + y)
pass
if __name__ == '__main__':
run(1, 2)
Example 3 - Advanced: Logging
import logging
def name(n):
def func(x, y):
res = n(x,y)
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(message)s', level=logging.DEBUG)
logging.info("执行了{},{},结果是{}".format(x,y,res))
return res
return func
@name
def run(x, y): # run = name(run)
return x+y
if __name__ == '__main__':
run(1, 2)
# 2023-03-01 12:24:10,474 root 20 ceshi_test.py 10 执行了1,2,结果是3
The result here does not seem to specify a function, and the impact is not great. You can look at the logging module, or you can add it yourself.
import logging
def name(n):
def func(x, y):
res = n(x,y)
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)
logging.info("执行了{},{},{},结果是{}".format(n.__name__,x,y,res))
return res
return func
@name
def run(x, y): # run = name(run)
return x+y
if __name__ == '__main__':
run(1, 2)
# 2023-03-01 12:35:15,283 root 20 ceshi_test.py 9 func 执行了run,1,2,结果是3
It can be seen that the obtained running functions are actually different. For accurate access, handwriting is recommended
Example 4 - Advanced: Time Timer
import time
def timer(clock):
def func(*args,**kwargs):
start = time.time()
res = clock(*args,**kwargs)
print("耗时 {} S".format(time.time() - start))
return res
return func
@timer
def run(x, y):
time.sleep(1)
print(x + y)
if __name__ == '__main__':
run(1, 2)
# 3
# 耗时 1.0103626251220703 S
The above is simply used to calculate the running time of the program without any operation.
Example 5 - Advanced - with parameters
def outwapper(out):
def country(cont):
def inwapper(*args,**kwargs):
if out == '中国':
print("你好啊,兄弟")
else:
print("你是哪个国家的")
cont(*args,**kwargs)
return inwapper
return country
@outwapper("中国")
def people():
pass
if __name__ == '__main__':
people()
Does it look like a lot of trouble, but it actually takes a long time to look at it carefully. Pass a parameter, the returned value still has to be returned.
def outwapper(out):
def country(cont):
def inwapper(*args,**kwargs):
if out == '中国':
print("你好啊,兄弟")
else:
print("你是哪个国家的")
cont(*args,**kwargs)
return inwapper
return country
@outwapper("中国")
@outwapper("俄罗斯")
def people():
pass
if __name__ == '__main__':
people()
# 你好啊,兄弟
# 你是哪个国家的
Multiple decorators can be applied to the same function and can be reused.
Example 6 - Higher Order - Class Decorator
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(args,kwargs)
@Time
def name():
pass
if __name__ == '__main__':
name()
Just apply the format, and the parameters in __init__ are necessary because the function needs to be passed.
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(args,kwargs)
@Time
def name(x,y):
pass
if __name__ == '__main__':
name('清安',age=18)
# ('清安',) {'age': 18}
Obviously, __call__ is used to receive and process values.
pass parameters
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, evt):
def wapper(*args, **kwargs):
print(self.func, args, kwargs)
return wapper
@Time("中国")
def name(x, y):
pass
if __name__ == '__main__':
name('清安', age=18)
# 中国 ('清安',) {'age': 18}
What is evt?
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, evt):
def wapper(*args, **kwargs):
print(evt.__name__, args, kwargs)
return wapper
@Time("中国")
def name(x, y):
print(x,y)
if __name__ == '__main__':
name('清安', age=18)
# name ('清安',) {'age': 18}
It is the function address of the name function, how to use the evt parameter?
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, evt):
def wapper(*args, **kwargs):
evt(args,kwargs)
# print(evt.__name__, args, kwargs)
return wapper
@Time("中国")
def name(x, y):
print(x,y)
if __name__ == '__main__':
name('清安', age=18)
It's that simple.
Example 7 - Higher Order - Decorator for Decorator Classes
def func(cls):
def inwapper(*args,**kwargs):
print(cls.__name__)
print(args)
return inwapper
@func
class User:
def __init__(self,name):
self.name = name
if __name__ == '__main__':
User("清an")
# User
# ('清an',)
Functions in classes use decorators
def func(cls):
def inwapper(x, *args, **kwargs):
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)
logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
return inwapper
# @func
class User:
@func
def name(self, name, name1, age):
# return name, name1, age
pass
if __name__ == '__main__':
u = User()
u.name("清安","ANAN",age=18)
2023-03-01 18:36:36,310 root 20 ceshi_test.py 74 inwapper 执行了name,结果是<__main__.User object at 0x0000020A11DABE50>,('清安', 'ANAN'),{'age': 18}
Why there is an x, because self will be passed as a parameter, and the memory address will be passed directly together, either the subscript value or another parameter to receive this self. Either self is not used in the class
❝Since self is used, can it be used to call properties in decorators? The answer is of course.
❞
def func(cls):
def inwapper(x, *args, **kwargs):
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)
x.info = 1
logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
return inwapper
class User:
info = None
@func
def name(self, name, name1, age):
# return name, name1, age
pass
if __name__ == '__main__':
u = User()
u.name("清安","ANAN",age=18)
print(u.info)
# 1
# 2023-03-02 09:15:36,640 root 20 ceshi_test.py 75 inwapper 执行了name,结果是<__main__.User object at 0x0000021B20A2F5B0>,('清安', 'ANAN'),{'age': 18}
❝Obviously, the assignment was successful. Let's look at assigning values to other functions.
❞
def func(cls):
def inwapper(x, *args, **kwargs):
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)
x.Info("QA",18)
logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
return inwapper
class User:
info = None
@func
def name(self, name, name1, age):
# return name, name1, age
pass
def Info(self,name,age):
print("我是{},今年{}".format(name,age))
if __name__ == '__main__':
u = User()
u.name("清安","ANAN",age=18)
# 2023-03-02 09:19:26,910 root 20 ceshi_test.py 75 inwapper 执行了name,结果是<__main__.User object at 0x00000232FF01F5B0>,('清安', 'ANAN'),{'age': 18}
# 我是QA,今年18
Example 8 - Masquerade
from functools import wraps
def timer(value):
def func(fun):
# @wraps(fun)
def inner(*args,**kwargs):
res = fun()
print(value)
print(inner.__name__)
return res
return inner
return func
@timer("QA")
def run():
pass
if __name__ == '__main__':
run()
❝Disguise the decorator so that the decorator function name points to the running function name.
❞
In addition, there are some usages, which will not be elaborated here. After learning the above examples, can you write a decent decorator yourself?