修饰方法上的 getattr 生成 TypeError

getattr on a decorated method generates a TypeError

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

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 中,"undecorated method" 会给出 <function __main__.A.undecorated_method>,但 getattr(A, "decorated_method") 仍然失败并显示 TypeError: __get__() takes 2 positional arguments but 3 were given。)

可能是什么原因造成的?我怎样才能找到给出的参数是什么?我如何调试 and/or 修复它?

getattr 将以下参数传递给 memoize__get__

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

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

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