Python当中所有东西都是对象,函数也不例外。所以要实现,在不改变一个函数的代码的情况下,给一个函数增加功能,可以在另一个函数里面调用这个函数,并执行别的功能。
def decorator(func):
def wrapper():
string = 'test'*2
func()
print(string)
# 此处返回一个函数的意思是,返回处理这个函数的对象。
return wrapper
def test():
print('本函数')
if __name__ == "__main__":
# 此处接收处理这个函数的对象,并对其进行调用
new_func = decorator(test)
new_func()
而装饰器就是上面这段程序的实现
def decorator(func):
def wrapper():
string = 'test'*2
func()
print(string)
return wrapper
@decorator
def test():
print('本函数')
if __name__ == "__main__":
test()
如果对一个函数调用多个装饰器,是由上往下的顺序,以递归的形式执行。这里可以使用pysnooper这个库,快速进行调试,查看执行的步骤。
import pysnooper
def order_test(func):
def wrapper():
print('+'*10)
func()
print('+'*10)
return wrapper
def order_test_another(func):
def wrapper():
print('-'*10)
func()
print('-'*10)
return wrapper
# @pysnooper.snoop()一个执行调试的库
@pysnooper.snoop(depth=3)
@order_test
@order_test_another
def ufunc():
print('I am the func')
if __name__ == "__main__":
ufunc()
输出结果
++++++++++
Starting var:.. func = <function order_test_another.<locals>.wrapper at 0x0000015F7AB45F28>
----------
14:57:10.321976 call 4 def wrapper():
I am the func
14:57:10.322972 line 5 print('+'*10)
----------
14:57:10.322972 line 6 func()
++++++++++
Starting var:.. func = <function ufunc at 0x0000015F7AB45EA0>
14:57:10.322972 call 11 def wrapper():
14:57:10.322972 line 12 print('-'*10)
14:57:10.322972 line 13 func()
14:57:10.322972 call 21 def ufunc():
14:57:10.322972 line 22 print('I am the func')
14:57:10.322972 return 22 print('I am the func')
Return value:.. None
14:57:10.322972 line 14 print('-'*10)
14:57:10.322972 return 14 print('-'*10)
Return value:.. None
14:57:10.322972 line 7 print('+'*10)
14:57:10.322972 return 7 print('+'*10)
Return value:.. None
对带有参数的函数使用装饰器
def _decorator(func):
def wrapper(cnt, sum):
print('传入的参数为', cnt, sum)
func(cnt, sum)
return wrapper
@_decorator
def myfunc(cnt, sum):
for i in range(cnt):
sum += i
print(sum)
if __name__ == '__main__':
myfunc(8, 0)
结果
传入的参数为 8 0
28
当然,参数也可以使用*args, **kwargs 代替
def decorator(func):
def wrapper(*args, **kwargs):
print('传入的参数为', *args, **kwargs)
func(*args, **kwargs)
return wrapper
@decorator
def myfunc(cnt, sum):
for i in range(cnt):
sum += i
print(sum)
if __name__ == '__main__':
myfunc(8, 0)
在类中使用装饰器,即装饰的是一个方法,python中方法和函数的区别就是方法的第一个参数的self,即对象本身。类中的装饰器内置有staticmethod,classmethod,property。
def decorate_method(method_func):
def wrapper(self, x):
x -= 10
return method_func(self, x)
return wrapper
def decorate_staticmethod(method_func):
def wrapper(x):
x = x**2
print('pow(x,2)=???')
return method_func(x)
return wrapper
class Test(object):
def __init__(self):
self.y = 15
@decorate_method
def sub(self, x):
print('x - self.y', '=', x - self.y)
@staticmethod
@decorate_staticmethod
def pow(x):
print('x*x = ', end='')
print(x)
if __name__ == '__main__':
test = Test()
test.sub(6)
Test.pow(6)
使用嵌套的装饰器函数接收任意的参数,这样便可以不用为传入参数的活而烦恼。
def decorator_with_args(decorator_to_enhance):
def decorator_maker(*args, **kwargs):
def decorator_wrapper(func):
return decorator_to_enhance(func, *args, **kwargs)
return decorator_wrapper
return decorator_maker
@decorator_with_args
def decorated_decorator(func, *args, **kwargs):
def wrapper(function_arg1, function_arg2):
print('Decorated with', args, kwargs)
return func(function_arg1, function_arg2)
return wrapper
@decorated_decorator(*list(range(10)))
def decorated_function(function_arg1, function_arg2):
print('Hello', function_arg1, function_arg2)
decorated_function('Universe and', 'everything')
输出结果
Decorated with (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) {}
Hello Universe and everything