[英]Class as decorator for class method
I want to use a decorator to do some prepare job and record the status the function have , so I write something like that : 我想使用装饰器做一些准备工作并记录函数具有的状态,所以我写了这样的东西:
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)
But it's obvious that self
in __call__(self, *args, **kwargs)
corresponds to instance of Decorator
instead of the instance of Foo
, which will make f.value
unchanged but f.test.value
increase . 但很明显, self
在__call__(self, *args, **kwargs)
对应的实例Decorator
,而不是实例Foo
,这将使f.value
不变,但f.test.value
增加。
Is there any way I can pass the instance of Foo
to Decorator
instead of Decorator
itself ? 有什么方法可以将Foo
实例传递给Decorator
而不是Decorator
本身?
Or is there any way to implement this function much more clear ? 还是有什么方法可以更清楚地实现此功能?
Thanks in advanced . 提前致谢 。
As the decorator is only called once and replaces the method for all instance with one instance of the Decorator class. 因为装饰器仅被调用一次,并用Decorator类的一个实例替换所有实例的方法。 All it does is: 它所做的就是:
Foo.test = Decorator(Foo.test)
This makes it impossible to detect the instance called. 这使得无法检测到调用的实例。 One work-around would be to apply the decorator in the __init__
of Foo
by hand: 一种解决方法是用手将装饰器应用于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)
This way the decorator wraps the instance method, so you do not need to pass self
in the __call__
of Decorator
: 装饰器通过这种方式包装实例方法,因此您无需在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)
Now it works and you have to update you test method, as f.test.value
no longer exists: 现在它可以工作了,您必须更新测试方法,因为f.test.value
不再存在:
f = Foo()
f.test(1)
print(f.value)
It outputs two times a 1
as expected. 它输出两倍于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
or May be this 或可能是这个
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))
I found using Priyesh Kumar's answer that you can simply pass the self argument from the call method to the function being decorated: 我发现使用Priyesh Kumar的答案,您可以将self参数从call方法简单地传递给要修饰的函数:
def __call__(self, *args, **kwargs):
return self.SafeGenerator(self.func(self, *args, **kwargs))
hope this helps! 希望这可以帮助!
EDIT: Never mind only works if the function being passed through the decorator does not call class variables defined in the init method 编辑:没关系,仅当通过装饰器传递的函数未调用init方法中定义的类变量时,才起作用
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.