Class 作为 class 方法的装饰器

Class as decorator for class method

我想用装饰器做一些准备工作并记录函数的状态,所以我写了这样的东西:

class Decorator:
    def __init__(self, func):
        self.count = 0
        self.func = func

    def __call__(self, *args, **kwargs):
        self.count += 1 # Simply count the call times
        return self.func(self, *args, **kwargs)

class Foo:
    def __init__(self):
        self.value = 0
    
    @Decorator
    def test(self, value):
        self.value = value # change the value of instance
        print(self.value)

f = Foo()
f.test(1)

print(f.value)
print(f.test.value) 

但很明显 __call__(self, *args, **kwargs) 中的 self 对应于 Decorator 的实例而不是 Foo 的实例,这将使 f.value 不变但f.test.value 增加 .

有什么方法可以将 Foo 的实例传递给 Decorator 而不是 Decorator 本身?

或者有什么方法可以更清楚的实现这个功能?

由于装饰器仅被调用一次,并且将所有实例的方法替换为装饰器的一个实例 class。它所做的只是:

Foo.test = Decorator(Foo.test)

这使得无法检测调用的实例。一种解决方法是手动在 Foo__init__ 中应用装饰器:

class Foo:
    def __init__(self):
        self.value = 0
        self.test = Decorator(self.test)

    def test(self, value):
        self.value = value # change the value of instance
        print(self.value)

这样装饰器就把实例方法包装起来了,这样就不用在Decorator__call__中传self了:

class Decorator:
    def __init__(self, func):
        self.count = 0
        self.func = func

    def __call__(self, *args, **kwargs):
        self.count += 1 # Simply count the call times
        return self.func(*args, **kwargs)

现在可以使用了,您必须更新测试方法,因为 f.test.value 不再存在:

f = Foo()
f.test(1)

print(f.value)

它按预期输出两倍 1

我知道了here

import functools

class Decorator(object):
    def __init__(self, func):
        self.count = 0
        self.func = func


    def __call__(self, *args, **kwargs):
        self.count += 1 # Simply count the call times
        return self.func( *args, **kwargs)

    def __get__(self, instance, instancetype):
        """Implement the descriptor protocol to make decorating instance 
        method possible.
        """

        # Return a partial function with the first argument is the instance 
        #   of the class decorated.
        return functools.partial(self.__call__, instance)



class Foo:
    def __init__(self):
        self.value = 0

    @Decorator
    def test(self, value):
        self.value = value # change the value of instance



f = Foo()
f.test(3)
print(f.value)  # prints 3


g = Foo()
g.test(8)
print(g.value) # prints 8

可能是这个

def preJob(function):
    def updateToDo(self, *args, **kwargs):
        # do some recording
        function(self, *args, **kwargs)
    return updateToDo

class Foo(object):
    def __init__(self):
        self.value = 0

    @preJob
    def test(self, value):
        self.value = value

f = Foo()
f.test(3)
print(f.value)  # prints 3


g = Foo()
g.test(8)
print(g.value) # prints 8
class threadSafeGenerator(object):
    """docstring for threadSafeGenerator"""
    class SafeGenerator(object):
        """docstring for SafeGenerator"""
        def __init__(self, iterable):
            self.iterable = iterable
            self.lock = Lock()
        def __iter__(self):
            return self

        def __next__(self):
            with self.lock:
                return next(self.iterable)

    def __init__(self, func):
        super(threadSafeGenerator, self).__init__()
        self.func = func

    def __call__(self, *args, **kwargs):
        return self.SafeGenerator(self.func(self, *args, **kwargs))

我发现使用 Priyesh Kumar 的回答,您可以简单地将 self 参数从 call 方法传递给被修饰的函数:

def __call__(self, *args, **kwargs):
    return self.SafeGenerator(self.func(self, *args, **kwargs))

希望对您有所帮助!

编辑: 没关系,仅当通过装饰器传递的函数不调用初始化方法

中定义的class变量时才有效