装饰器返回函数对象而不是包装函数的输出

校对员

抱歉,我只能想象 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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

对象函数返回函数而不是值

来自分类Dev

函数返回函数而不是对象

来自分类Dev

jwplayer 返回函数而不是播放器对象

来自分类Dev

返回函数的返回对象

来自分类Dev

返回函数而不是值

来自分类Dev

Strongloop相关模型返回函数,而不是对象

来自分类Dev

react-redux-firebase firestore返回函数而不是对象

来自分类Dev

Strongloop相关模型返回函数,而不是对象

来自分类Dev

返回函数外的对象

来自分类Dev

JS函数返回函数而不是值

来自分类Dev

返回带有包装器的函数对象

来自分类Dev

返回函数结果到输出参数

来自分类Dev

返回函数的函数,返回函数等

来自分类Dev

数据绑定返回函数而不是文本

来自分类Dev

wrapAsync 返回函数不是结果

来自分类Dev

函数返回函数?

来自分类Dev

javascript:如何从对象动态返回函数

来自分类Dev

简单的JavaScript函数返回函数而不是值

来自分类Dev

返回函数的输出作为main()的返回码

来自分类Dev

返回函数的代码

来自分类Dev

返回函数-PHP

来自分类Dev

用 && 返回函数?

来自分类Dev

OCaml:返回函数的函数

来自分类Dev

将迭代器返回函数转换为“适当的可迭代”返回函数的标准方法?

来自分类Dev

获取函数的同名,而不是装饰器的同名

来自分类Dev

引用类型返回函数:如何返回(可选)对象

来自分类Dev

返回函数表达式而不是结果

来自分类Dev

返回与不返回函数?

来自分类Dev

返回与不返回函数?