Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何避免python decorators函数中的名称冲突_Python_Python Decorators_Name Collision - Fatal编程技术网

如何避免python decorators函数中的名称冲突

如何避免python decorators函数中的名称冲突,python,python-decorators,name-collision,Python,Python Decorators,Name Collision,我想编写一个python decorator,以便引发异常的函数将再次运行,直到它成功,或者在放弃之前达到最大尝试次数 像这样: def tryagain(func): def retrier(*args,**kwargs,attempts=MAXIMUM): try: return func(*args,**kwargs) except Exception as e: if numberofattempts

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

像这样:

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
我的问题是,我想要一个保证,无论KWARG包含什么名称,都不会与用于表示尝试次数的名称发生冲突

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

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

other(x,y,attempts=z)

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

您可以指定decorator参数,如下所示:

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()

您可以指定decorator参数,如下所示:

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()

从函数属性获取重试尝试次数,而不是参数

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

    return retrier

@tryagain
def my_func(...):
    ...

my_func.attempts = 10
my_func()  # Will try it 10 times
要使调用函数时可以指定的内容最大化,请将定义更改为

def tryagain(maximum=10):
    def _(f):
        def retrier(*args, **kwargs):
            retries = getattr(func, "attempts", maximum)
            while retries + 1 > 0:
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    logging.error("Failed. Trying again")
                    last_exception = e
                retries -= 1
            else:
                logging.error("Tried %d times and failed, giving up", retries)
                raise last_exception
        return retrier
    return _
尽管仍然存在名称与尝试属性冲突的风险,但函数属性很少使用这一事实使得将tryagain记录为不使用具有预先存在的尝试属性的函数更为合理

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

    return retrier

@tryagain
def my_func(...):
    ...

my_func.attempts = 10
my_func()  # Will try it 10 times
我将修改tryagain以获取属性名作为参数作为练习:

@tryagain(15, 'max_retries')
def my_func(...):
    ...

这样,您可以在装修时选择一个未使用的名称。为此,您还可以使用tryagain的参数作为要添加到my_func的关键字参数的名称。

从函数属性获取重试次数,而不是参数

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

    return retrier

@tryagain
def my_func(...):
    ...

my_func.attempts = 10
my_func()  # Will try it 10 times
要使调用函数时可以指定的内容最大化,请将定义更改为

def tryagain(maximum=10):
    def _(f):
        def retrier(*args, **kwargs):
            retries = getattr(func, "attempts", maximum)
            while retries + 1 > 0:
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    logging.error("Failed. Trying again")
                    last_exception = e
                retries -= 1
            else:
                logging.error("Tried %d times and failed, giving up", retries)
                raise last_exception
        return retrier
    return _
尽管仍然存在名称与尝试属性冲突的风险,但函数属性很少使用这一事实使得将tryagain记录为不使用具有预先存在的尝试属性的函数更为合理

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

    return retrier

@tryagain
def my_func(...):
    ...

my_func.attempts = 10
my_func()  # Will try it 10 times
我将修改tryagain以获取属性名作为参数作为练习:

@tryagain(15, 'max_retries')
def my_func(...):
    ...

这样,您可以在装修时选择一个未使用的名称。为此,您还可以使用tryagain的参数作为要添加到my_func的关键字参数的名称。

如果要向修饰函数添加参数,然后,您必须记录使用的名称以及无法用该名称修饰已使用参数的函数的事实。您是否在问如果尝试是为您的函数命名的Kwarg之一会发生什么情况?@JoranBeasley是的,没错!另外,不要对此使用递归;它只是不必要地占用了堆栈空间。改用循环。你能提供一个出错的呼叫吗?理想情况下是实际的最小代码,而不是复杂的代码。如果要向修饰函数添加参数,然后,您必须记录使用的名称以及无法用该名称修饰已使用参数的函数的事实。您是否在问如果尝试是为您的函数命名的Kwarg之一会发生什么情况?@JoranBeasley是的,没错!另外,不要对此使用递归;它只是不必要地占用了堆栈空间。改用循环。你能提供一个出错的呼叫吗?理想情况下是实际的最小代码,而不是复杂的代码。这也有效地将尝试次数硬编码到新函数中,而不是您可以在运行时指定的次数。这也有效地将尝试次数硬编码到新函数中,而不是您可以在运行时指定的次数。