如何避免python decorators函数中的名称冲突
我想编写一个python decorator,以便引发异常的函数将再次运行,直到它成功,或者在放弃之前达到最大尝试次数 像这样:如何避免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
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是的,没错!另外,不要对此使用递归;它只是不必要地占用了堆栈空间。改用循环。你能提供一个出错的呼叫吗?理想情况下是实际的最小代码,而不是复杂的代码。这也有效地将尝试次数硬编码到新函数中,而不是您可以在运行时指定的次数。这也有效地将尝试次数硬编码到新函数中,而不是您可以在运行时指定的次数。