我想使用装饰器做一些准备工作并记录函数的状态,所以我写了类似的东西:
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
1}}增加。
有什么方法可以将Foo
的实例传递给Decorator
而不是Decorator
本身?
或者有没有办法更清楚地实现这个功能?
先谢谢。
答案 0 :(得分:4)
由于装饰器只被调用一次并用一个Decorator类的实例替换所有实例的方法。它所做的就是:
Foo.test = Decorator(Foo.test)
这使得无法检测到被调用的实例。一个解决方法是手动在__init__
Foo
中应用装饰器:
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)
这样装饰器会包装实例方法,因此您无需在self
的{{1}}中传递__call__
:
Decorator
现在它可以工作,你必须更新测试方法,因为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 :(得分:0)
我得到了这个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
答案 2 :(得分:0)
<section class="hero-area">
<div class="container">
<div class="row">
<div class="col-md-12">
<div style="margin-top:100px; margin-right:30px; height:506px; width:332px; float: right; background:url(images/Mobile-Screen.png)" >
<div class="play-backdrop"></div>
<div class="play-button">
<svg class="play-circles" viewBox="0 0 152 152">
<circle class="play-circle-01" fill="none" stroke="#fff" stroke-width="3" stroke-dasharray="343 343" cx="76" cy="76" r="72.7"/>
<circle class="play-circle-02" fill="none" stroke="#fff" stroke-width="3" stroke-dasharray="309 309" cx="76" cy="76" r="65.5"/>
</svg>
<div class="play-perspective">
<button class="play-close"></button>
<div class="play-triangle">
<div class="play-video">
<iframe width="600" height="400" src="https://www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</div>
</div>
</div>
</div>
</div>
我发现使用Priyesh Kumar的答案,您可以将self参数从 call 方法简单地传递给要修饰的函数:
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))
希望这会有所帮助!
编辑: 没关系,仅当通过装饰器传递的函数未调用init方法中定义的类变量时才起作用