首页 > 解决方案 > 如何避免 python 装饰器函数中的名称冲突

问题描述

我想编写一个python装饰器,以便再次运行引发异常的函数,直到它成功,或者在放弃之前达到最大尝试次数。

像这样:

def tryagain(func):
    def retrier(*args,**kwargs,attempts=MAXIMUM):
        try:
            return func(*args,**kwargs)
        except Exception as e:
            if numberofattempts > 0:
                logging.error("Failed. Trying again")
                return retrier(*args,**kwargs,attempts=attempts-1)
            else:
                logging.error("Tried %d times and failed, giving up" % MAXIMUM)
                raise e
    return retrier

我的问题是我想要保证无论 kwargs 包含什么名称,都不会与用于表示尝试次数的名称发生冲突。

attempts但是,当函数本身作为关键字参数时,这不起作用

@tryagain
def other(a,b,attempts=c):
    ...
    raise Exception

other(x,y,attempts=z)

在此示例中,如果运行 other,它将运行 z 次而不是 MAXIMUM 次(请注意,要发生此错误,必须在调用中显式使用关键字参数!)。

标签: pythonpython-decoratorsname-collision

解决方案


您可以指定装饰器参数,类似于以下内容:

import logging

MAXIMUM = 5

def tryagain(attempts=MAXIMUM):
    def __retrier(func):
        def retrier(*args,**kwargs):
            nonlocal attempts
            while True:
                try:
                    return func(*args,**kwargs)
                except Exception as e:
                    attempts -= 1
                    if attempts > 0:
                        print('Failed, attempts left=', attempts)
                        continue
                    else:
                        print('Giving up')
                        raise
        return retrier
    return __retrier


@tryagain(5)                              # <-- this specifies number of attempts
def fun(attempts='This is my parameter'): # <-- here the function specifies its own `attempts` parameter, unrelated to decorator
    raise Exception(attempts)

fun()

推荐阅读