用装饰器类装饰的方法没有冻结"self"参数

5 投票
1 回答
588 浏览
提问于 2025-04-16 15:28

我有一个用类定义的装饰器:

class predicated(object):
    def __init__(self, fn):
        self.fn = fn
        self.fpred = lambda *args, **kwargs: True

    def predicate(self, predicate):
        self.fpred = predicate
        return self

    def validate(self, *args, **kwargs):
        return self.fpred(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if not self.validate(*args, **kwargs):
            raise PredicateNotMatchedError("predicate was not matched")
        return self.fn(*args, **kwargs)

... 当我用它来包装一个类中的方法时,调用这个方法似乎没有把对象的实例作为第一个参数传进去。虽然这种情况并不算意外,但我该怎么做才能在这个方法变成实例方法的时候,让self保持不变呢?


简化的例子:

class test_decorator(object):
    def __init__(self, fn):
        self.fn = fn
    def __call__(self, *args, **kwargs):
        return self.fn(*args, **kwargs)

class Foo(object):
    @test_decorator
    def some_method(self):
        print(self)

Foo().some_method()

我本来期待能得到一个foo的实例,结果却出现了一个错误,提示说没有传递任何参数。

1 个回答

4

我搞明白了——需要定义一个 __get__ 方法,这样才能创建一个 MethodType 绑定,像这样:

def __get__(self, obj, objtype=None):
    return MethodType(self, obj, objtype)

这个方法在调用对象的方法时,会创建一个 MethodType 对象,并且会冻结 self 参数。

撰写回答