如何避免 python 装饰器函数中的名称冲突
How to avoid name collisions in python decorators functions
我想写一个 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 次(请注意,要发生此错误,必须在调用中显式使用关键字参数!)。
您可以指定装饰器参数,大致如下:
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
要使 MAXIMUM
成为您在调用装饰函数时可以指定的内容,请将定义更改为
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 _
尽管仍然存在与 attempts
属性发生名称冲突的风险,但很少使用函数属性这一事实使得将 tryagain
记录为不使用带有 pre 的函数更为合理-现有 attempts
属性。
(我将修改 tryagain
以将属性名称用作参数作为练习:
@tryagain(15, 'max_retries')
def my_func(...):
...
以便您在装修时选择一个未使用的名称。就此而言,您还可以使用 tryagain
的参数作为要添加到 my_func
的关键字参数的名称。)
我想写一个 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 次(请注意,要发生此错误,必须在调用中显式使用关键字参数!)。
您可以指定装饰器参数,大致如下:
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
要使 MAXIMUM
成为您在调用装饰函数时可以指定的内容,请将定义更改为
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 _
尽管仍然存在与 attempts
属性发生名称冲突的风险,但很少使用函数属性这一事实使得将 tryagain
记录为不使用带有 pre 的函数更为合理-现有 attempts
属性。
(我将修改 tryagain
以将属性名称用作参数作为练习:
@tryagain(15, 'max_retries')
def my_func(...):
...
以便您在装修时选择一个未使用的名称。就此而言,您还可以使用 tryagain
的参数作为要添加到 my_func
的关键字参数的名称。)