装饰器介绍
谈装饰器之前,需明白一件事,Python中的函数和Java、C++不一样,Python中的函数可以像普通变量一样当做参数传递给另外一个函数,代码示例如下:
def foo():
print('hello world')
def decorator(function):
function()
decorator(foo)
装饰器本质上是一个能返回函数的高阶函数,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
简单装饰器示例代码如下:
import logging
def use_logging(func):
def wrapper():
logging.warn("%s is running" % func.__name__)
return func()
return wrapper
def foo():
print('I am foo')
foo = use_logging(foo) # 因为装饰器 use_logging(foo) 返回的时函数对象 wrapper,这条语句相当于 foo = wrapper
foo()
程序输出如下:
WARNING:root:foo is running
I am foo
@语法糖
Python内置的@property 装饰器是负责把一个方法变成属性调用的,有了@,就可以省去foo = use_logging(foo)
这一句,直接调用foo()即可实现相同的功能。
def use_logging(func):
def wrapper():
logging.warn("%s is running" % func.__name__)
return func()
return wrapper
@use_logging
def foo():
print("i am foo")
foo()
有了Python的@语法,把decorator
置于函数foo定义处,调用foo函数,相当于执行语句foo = use_logging(foo)
。
args、*kwargs,可变参数与关键字参数
可以在定义wrapper函数的时候指定参数,参数可以是可变参数*args
、关键字参数**kwargs。
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
给wrapper函数添加参数的示例代码如下:
def wrapper(*args, **kwargs):
# args是一个数组,kwargs一个字典
logging.warn("%s is running" % func.__name__)
return func(*args, **kwargs)
return wrapper
带参数的装饰器
装饰器还有更大的灵活性,例如带参数的装饰器,在上面的装饰器调用中,该装饰器接收唯一的参数就是执行业务的函数 foo 。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)。示例代码如下:
def use_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "warn":
logging.warn("%s is running" % func.__name__)
elif level == "info":
logging.info("%s is running" % func.__name__)
return func(*args)
return wrapper
return decorator
@use_logging(level="info")
def foo(name='foo'):
print("i am %s" % name)
foo()
程序输出如下:
i am foo
装饰器示例
可打印函数运行时间的装饰器,代码如下:
# decorator: print the cost time of run function
def runTime(func):
def wapper(arg, *args, **kwargs):
print("function name: %s" %func.__name__)
start = time.time()
res = func(arg, *args, **kwargs)
end = time.time()
print("run time: %.2fs" %(end - start))
print("="*30)
return res
return wapper
总结
实现装饰器知识储备:
a、函数即“变量”
b、高阶函数
c、函数嵌套
d、高阶函数+嵌套函数==》装饰器
在面向对象( OOP)的设计模式中, decorator 被称为装饰模式。 OOP的装饰模式需要通过继承和组合来实现,而 Python 除了能支持 OOP 的decorator外,直接从语法层次支持 decorator。Python的decorator可以用函数实现,也可以用类实现。
参考资料