我正在尝试创建一个将发出api请求的类,根据传递给retrying.retry
装饰器的配置选项重试,并以正确的方式为每个作业处理不同的错误代码。
这是我的代码:
from retrying import retry
class APIRequester:
def __init__(self, url, **kwargs):
self.url = url
self.retry_kwargs = kwargs
@retry(**self.retry_kwargs) # Obviously doesn't know what self is
def make_request(self):
pass
如何将参数传递给此方法装饰器?我试过让它们成为一个类属性,它也不起作用。
答案 0 :(得分:3)
几个问题:
您是否知道@retry
装饰器将在创建课程时应用于make_request
方法 ,而retry_kwargs
将会仅在创建类的实例时才可用?
您是否知道前者必须先于后者?
在哪种情况下,您是否看到前者不能依赖后者可用的信息? ... 只要您使用装饰器语法 ...
您是否知道装饰器语法
@decorator
def xxx(...):
...
只是
的语法糖def xxx(...):
...
xxx = decorate(xxx)
如果您意识到这一点,以及Python非常动态,您可以通过执行类似
的操作来强制解决问题class APIRequester:
def __init__(self, url, **kwargs):
self.url = url
self.retry_kwargs = kwargs
APIRequester.make_request = retry(**kwargs)(APIRequester.make_request)
def make_request(self):
pass
这个特定的装饰者是否会在self
参数上窒息,我不能告诉你。
您是否有多个APIRequester
个实例?如果是这样,请注意每次创建新实例时都会重新修饰该方法:这可以合理地工作吗? (我对此表示怀疑。)但请看下面的编辑......
如果你没有更多的那个实例,那么你可能不需要依赖单身人士建造时可用的信息。
以上是一些通用的Python原则。我怀疑你真的希望在这种情况下强制解决问题。在我看来,你试图以一种不被设计使用的方式使用装饰器。
编辑:instancemethods
如果用
替换在构造函数中进行装饰的行self.make_request = retry(**kwargs)(self.make_request)
然后每个实例都将获得自己的函数装饰版本。这应该避免重新装饰相同功能的任何问题。 self
可能会遇到问题。在这种情况下,您可以从定义中删除self
参数并使用staticmethod
包装它:
self.make_request = retry(**kwargs)(staticmethod(self.make_request))
或者更好的是,使用装饰器语法将staticmethod
应用于make_request
到你定义它的地方,就像Guido所说的那样。
答案 1 :(得分:1)
当然,在调用时可以在装饰器中使用self。查看How to decorate a method inside a class?的答案,我的答案就在这里:
def my_retry(fn):
from functools import wraps
@wraps(fn)
def wrapped(self):
print(self.retry_kwargs)
for i in range(self.retry_kwargs["times"]):
# you have total control
fn(self)
# around your method. Can even call it multiple times,
# call with original retry:
retry(**self.retry_kwargs)(fn)(self)
# check exceptions, return some value (here None), etc
#
return wrapped
class APIRequester(object):
def __init__(self, url, **kwargs):
self.url = url
self.retry_kwargs = kwargs
@my_retry
def make_request(self):
print("method")
a = APIRequester('http://something', times=3)
a.make_request()
也就是说,原始装饰器被一个新的,配置感知的装饰器包裹起来。无需更改构造函数,语法仍然很简单。
答案 2 :(得分:1)
Decorator只是func=decorator(func)
的语法糖。你可以自己完成任务:
class APIRequester:
def __init__(self, url, **kwargs):
self.url = url
self.make_request = retry(**kwargs)(self.make_request)
def make_request(self):
pass
这将在内部用函数替换方法(描述符),但它将按预期工作。
答案 3 :(得分:0)
重试装饰器不支持类方法,因为类的实例被隐式传递给function。 请装饰正常功能。 如果要将函数包装到类中,请装饰静态方法。