关于 python 装饰器的理解
装饰器(Decorator)可以让其他函数在不需要做任何代码变动的前提下增加额外功能。简单的说,装饰器的作用就是为已经存在的函数或对象添加额外的功能。本质上,decorator 是一个返回函数的高阶函数。具体使用场景:插入日志、性能测试、事务处理、缓存、权限校验等场景。
之前通过实际代码学习和装饰器的具体用途。代码记录如下:
普通装饰器
python 提供了可变参数*args 和关键字参数**kwargs,有了这两个参数,装饰器可以用于带任意参数的目标函数。
import functools
# 普通装饰器,打印程序执行日志
def debug(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
print("[debug]: enter {}()".format(func.__name__))
return func(*args,**kwargs)
return wrapper
@debug
def say_goodbye(name):
print('goodbye,%s' % name)
say_goodbye(name='Fan')
带参数的装饰器
如果前文的装饰器需要完成的功能不仅仅是能在进入某个函数后打出 log 信息,而且还需指定 log 的级别,那么装饰器代码如下。
import functools
def log(level):
def debug(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
print("[debug] %s %s" % (level,func.__name__))
return func(*args,**kwargs)
return wrapper
return debug
@log(level='INFO')
def say_goodbye(name):
print('goodbye,%s' % name)
say_goodbye(name='Fan')
实例
通过装饰器测试程序执行时间。
import functools,time
def metic(func):
@functools.wraps(func)
def wrapper(*args,**kw):
start=time.time()
result=func(*args,**kw)
end=time.time()
print("%s excute time: %s ms" % (func.__name__,end-start))
return result
return wrapper
@metic
def fast(x,y):
time.sleep(0.1)
return x+y
@metic
def slow(x,y,z):
time.sleep(0.2)
return x*y*z
类装饰器
装饰器函数接受一个 callable 对象作为参数,然后返回一个 callable 对象。在 python 中一般 callable 对象都是函数,但也有例外。只要某个对象重载了call() 方法,那么这个对象就是 callable 的。类似call这样前后都带下划线的方法在 Python 中被称为内置方法,重载这些方法一般会改变对象的内部行为。
如下列代码所示,类的构造函数init() 接受一个函数,然后重载call() 并返回一个函数,也可以达到装饰器函数的效果。
import functools
class logging(object):
"""docstring for Test"""
def __init__(self,func):
self.func=func
def __call__(self,*args,**kw):
print("[DEBUG]:enter function {func}()".format(func=self.func.__name__))
return self.func(*args,**kw)
@logging
def test_logging(something):
print("test_logging %s !" % something)
test_logging('nothing')
带参数的类装饰器
如果需要通过类形式实现带参数的装饰器,那么在构造函数里接受的就不是一个函数,而是传入的参数。通过类把这些参数保存起来,然后再重载call方法是就需要接受一个函数并返回一个函数。
import functools
class Debug(object):
"""docstring for Debug"""
def __init__(self,level='INFO'):
super(Debug, self).__init__()
self.level = level
def __call__(self,func):
@functools.wraps(func)
def wrapper(*args,**kw):
print("Debug:[{level}] enter function {func}()".format(level=self.level,func=func.__name__))
func(*args,**kw)
return wrapper
@Debug(level='Warning')
def debug_test(func,name):
print("Hello,%s %s" % (func,name))
debug_test(func='Fan',name='Tongxue')
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论