装饰方法上的getattr会生成TypeError

时间:2016-06-30 03:17:25

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

我需要在实例级别应用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中,“未修饰的方法”会提供<function __main__.A.undecorated_method>,但getattr(A, "decorated_method")仍然会失败并显示TypeError: __get__() takes 2 positional arguments but 3 were given。)

可能导致什么?我怎样才能找到所给出的论点?我该如何调试和/或修复它?

1 个答案:

答案 0 :(得分:0)

getattr将以下参数传递给memoize&#39; __get__

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

这就是导致错误的原因。解决它:

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