def fun1():
print ('This is function 1')
当fun1 不能在满足我们当前的需求 需要在实现这个函数的同时加入其它功能,我们又想要去保存他的源码,那么我们需要去用到装饰器。
def fun2():
print ('This is function 2')
def fun1():
print ('This is function 3')
我们可以考虑一个问题,现在有多个函数(fun2,fun3……),我们同时要在这几个函数执行以后输出现在的时间,一一往这几个函数中加入输出这行命令是不现实的。
因此,装饰器的作用就会体现出来了。
装饰器:
def func1():
print('This is function 1')
def decorator(func):
def wrapper():
func()
pass
return wrapper
f = decorator(f1)
f()
这个定义方式是不是很懵逼,是的 我一时半会也没有理解他到底和新顶一个函数执行了函数func有什么大区别。
-------------------------------------------------------------
接下来介绍一下精髓 ‘@’
我们使用这种方法:
def decorator(func):
def wrapper():
func()
pass
return wrapper
@decorator
def func1():
print('This is function 1')
func1()
巧妙利用@可以让这种写法变得非常灵活。
----------------------------------------------------------
在函数带有参数的情况下,我们需要去注意:
def decorator(func):
def wrapper(string):
print ('123')
func(string)
return wrapper
@decorator
def func_str(name):
print (name)
func_str('test')
从上面我们可以看到在有参数的函数使用装饰器的时候,参数的位置该放的位置。
-------------------------------------------------------------
那么多个参数怎么办?
使用 '*'
def decorator(func):
def wrapper(*args):
print ('123')
func(*args)
return wrapper
接下来我们再来进一步改善这个装饰器
假设遇到关键字参数怎么办?
比如 :
@decorator
def func4(string1, string2, **keywords):
pass
这样的函数调用装饰器的时候我们会出错,这时候我们应该再改善装饰器成
def decorator(func):
def wrapper(*args,**keywords):
print ('123')
func(*args,**keywords)
return wrapper
----------------------------------------------------------------
之前我们看到的装饰器都是两层的函数,那么三层的函数呢??
如果装饰器本身需要传入参数,那么我们就需要在decorator外再包装一层
比如:
def log(text):
def decorator(func):
def wrapper(*args, **keywords):
print(text)
func(*args, **keywords)
return wrapper
return decorator
@log('Three-layer decorator')
def func4():
print('This is function 4')
--------------------------------------------------------
最大的注意之处!!!
在python中 函数也是一个对象
在我们使用了wrapper以后,实际上对原来的函数进行了修改 比如之前所讲的:
def decorator(func):
def wrapper(*args,**keywords):
print ('123')
func(*args,**keywords)
return wrapper
@decorator
def func4(string1, string2, **keywords):
pass
这里我们需要注意到的是 这时的func4.__name__已经发生了变化
>>> func4.__name__
'wrapper'
这时我们需要把原始函数的__name__
等属性复制到wrapper()
函数中,否则,有些依赖函数签名的代码执行就会出错。
所以我们要定义wrapper.__name__ = func.__name__ 这种操作???
答案是不需要的 在Python 中 functools.wraps 就是帮我们完成这样一件事的
所以最终版本的decorator需要是如下的形式:
import functools
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**keywords):
print ('123')
func(*args,**keywords)
return wrapper