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变量时才有效
我想用装饰器做一些准备工作并记录函数的状态,所以我写了这样的东西:
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变量时才有效