Write a decorator to apply another decorator with arguments for all methods of a class
来自这篇文章。这个被接受的答案很好地适用于不带任何争论的装饰师。我正试图扩展这个解决方案,使它为应用修饰器接受参数。
详细地说,我有进行外部API调用的函数。因为这些调用经常失败,所以我将retry decorator从这个库应用到所有函数。为了避免在所有函数中反复使用
注意:retry修饰符接受参数。
1 | @retry(wait_random_min=100, wait_random_max=300, stop_max_attempt_number=3) |
这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from retrying import retry def for_all_methods(decorator): def decorate(cls): for attr in cls.__dict__: if callable(getattr(cls, attr)): setattr(cls, attr, decorator(getattr(cls, attr))) return cls return decorate @for_all_methods(retry(wait_random_min=100, wait_random_max=300, stop_max_attempt_number=3)) class RetryClass(object): @classmethod def a(cls): pass def test(): RetryClass.a() return |
这将引发以下错误:
1 2 3 4 5 6 7 8 9 10 | Traceback (most recent call last): File"/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1596, in <module> globals = debugger.run(setup['file'], None, None, is_module) File"/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 974, in run pydev_imports.execfile(file, globals, locals) # execute the script File"/Users/gyoho/Datatron/Dev/class-decorator/main.py", line 26, in <module> test() File"/Users/gyoho/Datatron/Dev/class-decorator/main.py", line 22, in test RetryClass.a() TypeError: unbound method a() must be called with RetryClass instance as first argument (got nothing instead) |
但是,注释类修饰器运行时没有错误。我有什么东西不见了吗?
问题是,
1 2 3 4 5 6 | class RetryClass(object): @retry(wait_random_min=100, wait_random_max=300, stop_max_attempt_number=3) @classmethod def a(cls): pass |
您的课程需要相当于:
1 2 3 4 5 6 | class RetryClass(object): @classmethod @retry(wait_random_min=100, wait_random_max=300, stop_max_attempt_number=3) def a(cls): pass |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | def decorate(cls): for attr in cls.__dict__: possible_method = getattr(cls, attr) if not callable(possible_method): continue if not hasattr(possible_method,"__self__"): raw_function = cls.__dict__[attr].__func__ decorated_method = decorator(raw_function) decorated_method = staticmethod(decorated_method) if type(possible_method.__self__) == type: raw_function = cls.__dict__[attr].__func__ decorated_method = decorator(raw_function) decorated_method = classmethod(decorated_method) elif possible_method.__self__ is None: decorated_method = decorator(possible_method) setattr(cls, attr, decorated_method) return cls |