Fed*_*ega 5 wrapper python-3.x python-decorators
我一直在研究如何创建自己的装饰器,并给出了以下示例:
def counter(func):
def wrapper(*args, **kwargs):
wrapper.count += 1
# Call the function being decorated and return the result
return wrapper.count
wrapper.count = 0
# Return the new decorated function
return wrapper
# Decorate foo() with the counter() decorator
@counter
def foo():
print('calling foo()')
foo()
foo()
print('foo() was called {} times.'.format(foo.count))
Run Code Online (Sandbox Code Playgroud)
我不明白那段代码的逻辑。
wrapper.count)?
- 如何引用自身内部的函数(wrapper.count)?
函数体仅在调用时才会执行。到那时,该函数已经被定义,因此这使得它成为可能。以下不会给你任何错误,除非你调用它:
>>> def foo():
... non_existing_function()
...
Run Code Online (Sandbox Code Playgroud)
每当您进入 的正文时foo,foo已经定义,因此您可以引用它。这也是递归调用成为可能的原因。
- 在定义包装器之前,包装器如何拥有方法计数?
问题也可能是“我如何wrapper.count在初始化之前增加它? ”
但同样,我们可以用同样的方式回答这个问题:因为函数体在我们调用它们之前不会被执行,所以在wrapper.count之前初始化为 0 wrapper.count += 1。
- 每次我调用 foo() 时,不应该执行wrapper.count = 0 行吗?
让我们看看发生了什么。你写:
@counter
def foo():
print('calling foo()')
Run Code Online (Sandbox Code Playgroud)
这只是一个语法糖:
foo = counter(foo)
Run Code Online (Sandbox Code Playgroud)
现在,我们以参数调用counter函数。foo有什么counter作用?
def counter(func):
def wrapper(*args, **kwargs):
wrapper.count += 1
# Call the function being decorated and return the result
return wrapper.count
wrapper.count = 0
# Return the new decorated function
return wrapper
Run Code Online (Sandbox Code Playgroud)
用人类语言来说,
wrapper,该函数采用未知数量的位置参数和关键字参数0属性countwrapperwrapper给调用者当我们将结果分配回函数时foo,我们实际上已经分配wrapper给了foo. 所以当我们打电话时foo,我们实际上是在打电话wrapper。该行wrapper.count = 0位于wrapper函数外部,因此它不会在我们每次调用时运行foo。
最后,我强烈建议您观看Reuven M. Lerner关于装饰器的精彩 PyCon 演讲。
编辑:我没有阅读包装器的正文,这实际上证明您并不真正需要知道包装器内部的内容。我的解释仍然是正确的。但是,正如@Mark Tolonen 的回答中所建议的,你的包装器可能应该返回func(*args,**kwargs) 不 wrapper.count