##前言
装饰器(Decorator)是python的一个重要部分。简单地说:他是利用语法糖,封装函数,以实现函数的功能。他们有助于让我们的代码更简短,也更Pythonic(Python范儿),这篇记录常用功能,以防遗忘
装饰器简单使用(打log)
In [1]:
def logging(func):
def wrapper():
print("%s is running" % func.__name__)
return func()
return wrapper
@logging
def yancy():
print("i am yancy")
yancy()
Out[2]:
yancy is running
i am yancy
这个代码里,logging就是一个装饰器函数,他的作用就是在调用方法是打印出方法的名字,使用方法也很简单 直接就在想用使用的方法上加上@logging就可以,这个@就是python的语法糖,装饰器可重复利用性,并增加了程序的可读性。
带参数装饰器(*args, **kwargs)
简单的装饰器可以实现一些简单的功能,但是上面的装饰器有个问题,如果yancy方法有参数,而我们现在装饰器中处理参数, 那就要用到带参数的装饰器了
In [1]:
def logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
print(level)
return func(*args)
return wrapper
return decorator
@logging('yancy')
def foo(name='yancy'):
print("i am %s" % name)
foo()
Out [2]:
yancy
i am yancy
这里我们通过嵌套一层方法的方式传递参数,传递的参数可以使str、list、dict
类装饰器
装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。
In [1]:
class logging(object):
def __init__(self, func):
self._func = func
def __call__(self):
print('class decorator runing')
self._func()
print('class decorator ending')
@logging
def foo():
print('yancy')
foo()
Out [2]:
class decorator runing
yancy
class decorator ending
functools.wraps
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的__name__、参数列表,先看例子:
In [1]:
def logging(func):
def wrapper():
print("%s is running" % func.__name__)
return func()
return wrapper
@logging
def yancy():
print("i am yancy")
print(yancy.__name__)
Out [2]:
wrapper
这个问题就大了,用我们老大的一句话就是:怎么解决那,还好我们有functools.wraps
In [1]:
from functools import wraps
def logging(func):
@wraps(func)
def wrapper():
print("%s is running" % func.__name__)
return func()
return wrapper
@logging
def yancy():
print("i am yancy")
print(yancy.__name__)
Out [2]:
yancy
wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器里面的 func 函数中,这使得装饰器里面的 func 函数也有和原函数 foo 一样的元信息了。
装饰器顺序
In [1]:
@a
@b
@c
def f ():
pass
装饰器的执行顺序很简单的了,就是从上到下