昨天了解了python 装饰器的部分概念,今天继续昨天的内容稍作分析。首先还是来看一个装饰器
import time
def log(func):
def wrapper(*args, **kw):
print('func %s() is running' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
@符号是python 装饰器的语法糖。早期的写法是,定义好了装饰器后
now = log(now)
是将装饰器函数赋值给被装饰函数的同名变量。这种写法不太优雅,所以才在后续版本中加入了@语法糖的写法
带参数的装饰器
装饰器本质上是一个函数, python 是支持将函数本身赋值给变量的。 下面来看一个带参数的装饰器
import time
def log(level):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print("[{level}]: enter function {func}".format(level=level, func=func.__name__)
return func(*args, **kwargs)
return inner_wrapper
return wrapper
@log(level='INFO')
def now():
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
这是一个带参数的装饰器,可以看到跟之前不带参数的装饰器相比,他多了一层结构,在wrapper 函数里面又定义了一层 inner_wrapper 方法。 这里的理解方式是: 当调用@log(level='INFO')时,可以将最外面一层看作是一个函数,函数返回的是一个装饰器。
functools
python 装饰器跟python 能够将函数对象赋值给变量的特性是密不可分的。当我们将 装饰器赋值给变量,然后打印 变量的函数名时,会出现装饰器内部的函数名。这时可以使用 functools
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
在wrapper 定义之前 @function.wraps(func) 就可以避免上述的情况发生。
参考文档:
1、廖雪峰的python教程
2、 详解python装饰器
网友评论