Python 装饰器未按预期运行
Python decorator not acting as expected
只是在玩装饰器,还有我做的一个简单的例子。我期望每次调用方法时,方法名称都会被添加到列表中。
python_func_calls = []
def log_func_call(func):
python_func_calls.append(func.__name__)
return func
@log_func_call
def print_a():
print('I am the a function...')
@log_func_call
def print_b():
print('I am the b function...')
print_a()
print_b()
print_b()
print_a()
print(python_func_calls)
但这给了我 python_func_calls 的以下内容:
['print_a', 'print_b']
我原以为列表中会有 4 个条目,因为装饰函数被调用了 4 次。
您需要创建一个新函数和 return that 装饰器。在此函数内,调用传入的包装函数。例如:
from functools import wraps
python_func_calls = []
def log_func_call(func):
@wraps(func)
def wrapped(*args, **kwargs):
python_func_calls.append(func.__name__)
func(*args, **kwargs)
return wrapped
@log_func_call
def print_a():
print('I am the a function...')
@log_func_call
def print_b():
print('I am the b function...')
print_a()
print_b()
print_b()
print_a()
print(python_func_calls)
这使得 python_func_calls
为:
['print_a', 'print_b', 'print_b', 'print_a']
这样做的原因是装饰器 returned 的函数替换了包装函数。所以它每次都会被调用,而不仅仅是当装饰器是 created.In 你的原始代码时,你 return 原始函数......所以当你调用函数时没有任何改变。
装饰器在函数定义处被调用所以总共调用了两次:
python_func_calls = []
def log_func_call(func):
python_func_calls.append(func.__name__)
return func
@log_func_call #first call
def print_a():
print('I am the a function...')
@log_func_call #second call
def print_b():
print('I am the b function...')
print_a() #decorator not called
print_b() #decorator not called
print_b() #decorator not called
print_a() #decorator not called
print(python_func_calls)
所以尽管有 4 个函数调用,但只有 2 个装饰器调用。
装饰器语法类似于:
def print_a():
...
print_a = log_func_call(print_a)
因此,装饰器仅以目标函数作为参数被调用一次。如果您希望装饰版本为每个函数调用做额外的工作,您需要在装饰器中创建一个包装函数来做两件事:
- 做额外的工作:
python_func_calls.append(func.__name__)
- 调用装饰函数和 return 无论那个函数 returns:
return func(*args, **kwargs)
.
以下装饰器实现了这些要求:
from functools import wraps
python_func_calls = []
def log_func_call(func):
@wraps(func)
def wrapper(*args, **kwargs):
python_func_calls.append(func.__name__)
return func(*args, **kwars)
return wrapper
请注意,装饰器使用另一个装饰器 wraps
,它调整 wrapper
函数的元数据以模仿装饰函数 func
的元数据(例如签名和文档字符串)。
只是在玩装饰器,还有我做的一个简单的例子。我期望每次调用方法时,方法名称都会被添加到列表中。
python_func_calls = []
def log_func_call(func):
python_func_calls.append(func.__name__)
return func
@log_func_call
def print_a():
print('I am the a function...')
@log_func_call
def print_b():
print('I am the b function...')
print_a()
print_b()
print_b()
print_a()
print(python_func_calls)
但这给了我 python_func_calls 的以下内容:
['print_a', 'print_b']
我原以为列表中会有 4 个条目,因为装饰函数被调用了 4 次。
您需要创建一个新函数和 return that 装饰器。在此函数内,调用传入的包装函数。例如:
from functools import wraps
python_func_calls = []
def log_func_call(func):
@wraps(func)
def wrapped(*args, **kwargs):
python_func_calls.append(func.__name__)
func(*args, **kwargs)
return wrapped
@log_func_call
def print_a():
print('I am the a function...')
@log_func_call
def print_b():
print('I am the b function...')
print_a()
print_b()
print_b()
print_a()
print(python_func_calls)
这使得 python_func_calls
为:
['print_a', 'print_b', 'print_b', 'print_a']
这样做的原因是装饰器 returned 的函数替换了包装函数。所以它每次都会被调用,而不仅仅是当装饰器是 created.In 你的原始代码时,你 return 原始函数......所以当你调用函数时没有任何改变。
装饰器在函数定义处被调用所以总共调用了两次:
python_func_calls = []
def log_func_call(func):
python_func_calls.append(func.__name__)
return func
@log_func_call #first call
def print_a():
print('I am the a function...')
@log_func_call #second call
def print_b():
print('I am the b function...')
print_a() #decorator not called
print_b() #decorator not called
print_b() #decorator not called
print_a() #decorator not called
print(python_func_calls)
所以尽管有 4 个函数调用,但只有 2 个装饰器调用。
装饰器语法类似于:
def print_a():
...
print_a = log_func_call(print_a)
因此,装饰器仅以目标函数作为参数被调用一次。如果您希望装饰版本为每个函数调用做额外的工作,您需要在装饰器中创建一个包装函数来做两件事:
- 做额外的工作:
python_func_calls.append(func.__name__)
- 调用装饰函数和 return 无论那个函数 returns:
return func(*args, **kwargs)
.
以下装饰器实现了这些要求:
from functools import wraps
python_func_calls = []
def log_func_call(func):
@wraps(func)
def wrapper(*args, **kwargs):
python_func_calls.append(func.__name__)
return func(*args, **kwars)
return wrapper
请注意,装饰器使用另一个装饰器 wraps
,它调整 wrapper
函数的元数据以模仿装饰函数 func
的元数据(例如签名和文档字符串)。