- import time
- def decorator(func):
- def wrapper(*args, **kwargs):
- start_time = time.time()
- func()
- end_time = time.time()
- print(end_time - start_time)
- return wrapper
- @decorator # @decorator 相当于 test = decorator(test)
- def test():
- time.sleep(0.8)
- print("test 源代码")
- # 函数调用
- test()
在上面代码中 test 是我要装饰器的函数, 我想用装饰器显示 test 函数运行的时间.@decorator 这个语法相当于 执行 test= decorator(test), 为 test 函数装饰并返回.
再来看一下我们的装饰器函数 decorator, 该函数的传入参数是 func (即被装饰函数 test 的引用), 返回参数是内层函数. 这里的内层函数 wrapper, 其实就相当于闭包函数, 它起到装饰给定函数的作用.
4.2 被装饰的函数有不定长参数
- import time
- def timefun(func):
- def wrapped_func(*args, **kwargs):
- print("%s called at %s" % (func.__name__, time.ctime()))
- func(*args, **kwargs)
- return wrapped_func
- @timefun
- def foo(a, b, c, d="foo 原代码"):
- time.sleep(0.8)
- print(a + b + c)
- print(d)
- foo(3, 5, 7)
运行结果:
wrapper 参数为 * args, **kwargs. *args 表示的参数以列表的形式传入;**kwargs 表示的参数以字典的形式传入:
从图中我们可以看到: 凡是以 key=value 形式的参数均存在 kwargs 中, 剩下的所有参数都以列表的形式存于 args 中. 这里要注意的是: 为了不破坏原函数的逻辑, 我们要保证内层函数 wrapper_func 和被装饰函数 func 的传入参数和返回值类型必须保持一致.
4.3. 类装饰器
前面我们提到的都是让 函数作为装饰器去装饰其他的函数或者方法, 那么可不可以让 一个类发挥装饰器的作用呢? 答案肯定是可以的, python 中一切皆对象, 函数和类本质没有什么不一样.
- class Decorator(object):
- def __init__(self, f):
- self.f = f
- def __call__(self):
- print("decorator start")
- self.f()
- print("decorator end")
- @Decorator
- def func():
- print("func")
- func()
这里值得注意的是:__call__() 是一个特殊方法, 它可将一个类实例变成一个可调用对象:
- func = Decorator(func) # func 是类 Decorator 的一个实例
- func() # 实现了__call__() 方法后, func 可以被调用
要使用类装饰器必须实现类中的__call__() 方法, 就相当于将实例变成了一个方法.
来源: https://www.cnblogs.com/new-rain/p/9975025.html