繁体   English   中英

类作为类方法的装饰器

[英]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) 

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

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

还是有什么方法可以更清楚地实现此功能?

提前致谢 。

因为装饰器仅被调用一次,并用Decorator类的一个实例替换所有实例的方法。 它所做的就是:

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的预期值。

我在这里

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))

希望这可以帮助!

编辑:没关系,仅当通过装饰器传递的函数未调用init方法中定义的类变量时,才起作用

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM