抱歉,我只能想象 StackOverflow 上到处都是几乎在那里的人,但仍然不太了解装饰者。
我试图装饰一系列与os相关的功能,以便如果出现FileNotFoundError或PermissionError等任何异常,用户可以解决问题并重试。
所以我创建了这个玩具函数和装饰器,我不明白我在哪里没有正确遵循我一直在阅读的示例装饰器,而且我在推理过程中遇到了麻烦:
from functools import wraps
def continual_retry(func):
def retry_decorated(*args, **kwargs):
@wraps(func)
def func_wrapper(*args, **kwargs):
while not stop:
try:
func(*args)
stop = True
except Exception as e:
print(f'Could not perform function {func.__name__}')
print(f' with args {repr(args)}')
print(f' due to error {e.class__}')
redo = input('Retry (y/n)? ')
if redo.lower() != 'y':
print('Exiting program due to error and user input')
sys.exit(0)
return func_wrapper
return retry_decorated
@continual_retry
def divide(a, b):
return a/b
当我运行函数时divide
,结果如下:
>>> divide(1, 2)
<function __main__.divide(a, b)>
我期待的结果
0.5
(然后我要去测试divide(1, 0)
)
你的装饰器是一个装饰器工厂,它返回另一个装饰器。这里不需要工厂,去掉一层:
def continual_retry(func):
@wraps(func)
def func_wrapper(*args, **kwargs):
while True:
try:
return func(*args, **kwargs)
except Exception as e:
print(f'Could not perform function {func.__name__}')
print(f' with args {repr(args)}')
print(f' due to error {e.class__}')
redo = input('Retry (y/n)? ')
if redo.lower() != 'y':
print('Exiting program due to error and user input')
sys.exit(0)
return func_wrapper
您还需要返回函数 result,我将while
循环更改为无限循环while True:
,因为成功return
将退出循环。我还更新了func()
对传递关键字参数 ( return func(*args, **kwargs)
)的调用。
当 Python 遇到 时@continual_retry
,它会将函数对象传递给continual_retry()
可调用对象以用结果替换该函数,就像您期望的那样divide = continual_retry(divide)
,但在您的版本中continual_retry(divide)
返回的是retry_decorated()
函数,该函数本身在被调用时最终返回func_wrapper
对象。你想func_wrapper
被用来替代。
当您想配置装饰器时,您的双层方法非常有用,其中外部装饰器工厂函数接受函数以外的参数。目标是然后使用它,@continual_retry(config_arg1, config_arg2, ...)
以便 Python 首先调用该函数以获取返回值,然后通过调用该返回值进行修饰。
例如,您可以添加一个选项来限制重试次数:
def continual_retry(limit=None):
def retry_decorator(func):
@wraps(func)
def func_wrapper(*args, **kwargs):
retries = 0
while True
try:
return func(*args, **kwargs)
except Exception as e:
print(f'Could not perform function {func.__name__}')
print(f' with args {repr(args)}')
print(f' due to error {e.class__}')
redo = input('Retry (y/n)? ')
if redo.lower() != 'y':
print('Exiting program due to error and user input')
sys.exit(0)
retries += 1
if limit is not None and retries > limit:
# reached the limit, re-raise the exception
raise
return func_wrapper
return retry_decorator
现在您必须在装饰时使用@continual_retry()
或@continual_retry(<integer>)
,例如:
@continual_retry(3)
def divide(a, b):
return a / b
因为它continual_retry()
产生了装饰器,并continual_retry(3)(divide)
产生了替换原始函数的包装器。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句