装饰器,就是一个用来装饰的东西;
它长这样子:
@xxx
其中,@
是它的语法糖,xxx
是它的名字;
装饰器实际上就是一个函数;
他能装饰函数
、类
;
在项目中,当你写了很多函数,你想知道运行时都有哪些函数在执行,
而且,你又不想写测试;
那么,你可以这样:
def foo(arg):
print('%s is running' % foo.__name__)
这样虽然可以,但是你不觉得在每个函数后面加上这一行很麻烦么?
等你加完,测试完后,又得一个个删除,你不觉得‘蓝瘦香菇么’?
不过,你如果了解装饰器,那么,你可以这样写:
def my_log(func):
def wrapper(*args, **kwargs):
print(''%s is running' % func.__name__)
return wrapper
@my_log
def foo(arg):
print('i`m foo')
@my_log
def_foo1(arg)
print('i`m foo1')
其中,my_log
函数就是装饰器;
这样你就可以把@my_log
加在需要装饰的函数前面;
不需要的时候再全局搜索删除即可;
如此,方便又快捷;
装饰器实质上就是一个函数
;
要理解装饰器原理,我们可以回到刚刚那个问题;
假装你还不知道装饰器;
你再三思考;
想到了这样的一个方法:
def foo():
pass
def foo1():
pass
def foo2():
pass
def print_log():
print ('foo is running')
foo()
print ('foo1 is running')
foo1()
print ('foo2 is running')
foo2()
这样看起来还不错,避免修改原来的函数;
但是,每个函数都得写一次print;
感觉太麻烦;
于是,你优化了一下代码:
def print_log(func):
print('%s is running' % func.__name__)
func()
print_log(foo)
print_log(foo1)
print_log(foo2)
这样省去很多个print,看起来好多了;
但是,当你想到出现这种情况的时候:
def main():
print_log(foo)
a = print_log(foo1)
b = print_log(foo2) + m
for i in print_log(foo):
i = i + n
看到满屏幕的print_log
,感觉好恐怖;
于是,又想到一个办法:
def print_log(func):
print('%s is running' % func.__name__)
return func
foo = print_log(foo)
foo1 = print_log(foo1)
foo2 = print_log(foo2)
foo()
foo1()
foo2()
这样用回了原来的函数名,舒服,一看就懂;
但是,如果这些函数是带参数的,要怎么办呢?
显然,这方法对带参数的函数是不行的;
你想着这样写:
foo = print_log(foo(arg))
但是,细想又不对,foo本应该是作为参数对象,加上括号后foo就直接被执行了;
foo需要做的只是静静的呆着,而不是执行起来,这,不是你想要的;
一顿冥思苦想之后,你想起了返回函数
;它,可以接收参数!
def print_log(func):
def wrapper(*arg, **kwargs):
print('%s is running' % func.__name__)
return func(*arg, **kwargs)
return wrapper
foo = print_log(foo)
foo(1)
这样,foo = print_log(foo)
就相当于把foo
指向了wrapper
;
而wrapper
可以有参数,那么,foo也可以有参数了;
这样,需求实现,完美~
但是,foo = print_log(foo)
可不可以自动完成呢?
可以,定个规则,@print_log
,取名装饰器;
呼呼~突出一口浊气;
人生苦短,来学python;
以为这样就是结局了么?
装饰器如果也需要参数,那怎么办?
emmm....
那就加多一层呗:
def log(args):
def print_log(func):
def wrapper(*arg, **kwargs)
print('%s is running' % func.__name__)
print(args
return func(*arg, **kwargs)
return wrapper
return log
到此,装饰器就差不多了;
等等,你运行代码后又发现,执行结果不对呀;func.__name__
变成了wrapper
了;
这时候,只需要在wrapper前面加上 wrapper.__name__ = func.__name__
即可;
def log(args):
def print_log(func):
def wrapper(*arg, **kwargs)
wrapper.__name__ = func.__name__
print('%s is running' % func.__name__)
print(args
return func(*arg, **kwargs)
return wrapper
return log
Python内置的functools.wraps,就可以实现wrapper.__name__ = func.__name__
;
只需要在wrapper函数前面加上 @functools.wraps(func)
即可;
import functools
def log(args):
def print_log(func):
@functools.wraps(func)
def wrapper(*arg, **kwargs)
print('%s is running' % func.__name__)
print(args
return func(*arg, **kwargs)
return wrapper
return log
本文为Larwas原创文章,转载无需和我联系,但请注明来自larwas博客 https://larwas.com
最新评论