【问题标题】:getattr on a decorated method generates a TypeError装饰方法上的 getattr 会生成 TypeError
【发布时间】:2016-11-01 23:26:44
【问题描述】:

我需要在实例级别应用 memoization,所以我使用了以下装饰器:

from functools import partial, update_wrapper

class memoize(object):
    def __init__(self, func):
        self.func = func
        update_wrapper(self, func)

    def __get__(self, obj):
        if obj is None:
            return self.func
        return partial(self, obj)

    def __call__(self, *args, **kwargs):
        obj = args[0]
        try:
            cache = obj.__cache__
        except AttributeError:
            cache = obj.__cache__ = {}
        key = (self.func, args[1:], frozenset(kwargs.items()))
        try:
            res = cache[key]
        except KeyError:
            res = cache[key] = self.func(*args, **kwargs)
        return res

应用:

class A(object):
    def __init__(self, parent):
        self.parent = parent

    def undecorated_method(self, pose, frame):
        pass

    @memoize
    def decorated_method(self, pose, frame):
        pass

我发现可以访问它的唯一方法是执行A.__dict__["decorated_method"]。尝试 getattr(A, "decorated_method")getattr(A(5), "decorated_method")A.decorated_method 等都失败了:

TypeError: __get__() takes exactly 2 arguments (3 given)

真实代码的实际回溯是:

Traceback (most recent call last):
  File "./regenerate_launch_files.py", line 145, in <module>
    main()
  File "./regenerate_launch_files.py", line 130, in main
    verify_coeffs(method, past_image_keys)
  File "./regenerate_launch_files.py", line 117, in verify_coeffs
    if not (inspect.ismethod(getattr(evaluator, component))
TypeError: __get__() takes exactly 2 arguments (3 given)

调用未修饰的方法没有问题。

>>> getattr(A, "undecorated_method")
<unbound method __main__.A.undecorated_method>

(在 Python 3 中,“未修饰的方法”会给出 &lt;function __main__.A.undecorated_method&gt;,但 getattr(A, "decorated_method") 仍然会失败并返回 TypeError: __get__() takes 2 positional arguments but 3 were given。)

可能是什么原因造成的?我怎样才能找到给出的论点是什么?如何调试和/或修复它?

【问题讨论】:

    标签: python python-2.7 decorator python-3.5 python-decorators


    【解决方案1】:

    getattr 将以下参数传递给memoize__get__

    * `self`
    * `None`
    * `<class '__main__.A'>`
    

    这就是导致错误的原因。修复它:

    def __get__(self, instance, owner):
        if instance is None:
            return self.func
        return partial(self, instance)
    

    【讨论】:

      猜你喜欢
      • 2017-01-20
      • 2019-11-19
      • 1970-01-01
      • 2017-11-02
      • 2017-01-09
      • 2017-04-17
      • 1970-01-01
      • 2020-02-05
      • 2011-08-02
      相关资源
      最近更新 更多