改变对象状态的装饰器
Decorator to change the state of an object
我想创建一个class继承到别处,用装饰器把具体的方法存放在一个属性中
我尝试了以下装饰器
def filtermethod(f):
def wrapped(self, *args, **kwargs):
self.methods.append(f)
return f(self, *args, **kwargs)
return wrapped
并用
定义classes
class foo:
def __init__(self):
self.methods = []
def apply_filter(self, x):
for fun in self.methods:
x = fun(x)
return x
class foo2(foo):
@filtermethod
def method1(self, x):
return [i for i in x if i > 5]
@filtermethod
def method2(self, x):
return [i for i in x if i < 18]
并使用以下
测试class
foo2().apply_filter([1, 4, 1, 5, 73, 25, 7, 2, 26, 13, 46, 9])
并希望所有装饰函数都应用到参数,但我明白了
[1, 4, 1, 5, 73, 25, 7, 2, 26, 13, 46, 9]
而不是
[7,13,9]
基本上,我想将每个用 @filtermethod
修饰的函数附加到属性 self.methods
,(与 self.apply_filter
连续应用) 但我根本做不到。
有什么线索吗?
filtermethod
本身在创建 class 时被调用。因此,您需要在 class 级别上做一些事情。
下面,我更改了您的代码以展示其工作原理。我所做的就是让装饰器用一个变量标记它包装的函数,__init_subclass__
获取并添加到 _methods
(作为未绑定方法)。
def filtermethod(f):
f._is_filter_method = True
return f
class foo:
def __init_subclass__(cls, **kwargs):
funcs = (getattr(cls, v) for v in dir(cls))
cls._methods = [f for f in funcs if hasattr(f, '_is_filter_method')]
def apply_filter(self, x):
for fun in self._methods:
x = fun(self, x)
return x
class foo2(foo):
@filtermethod
def method1(self, x):
return [i for i in x if i > 5]
@filtermethod
def method2(self, x):
return [i for i in x if i < 18]
class foo3(foo2):
@filtermethod
def method1(self, x):
return [i for i in x if i == 4]
编辑:修复了覆盖
如果您 运行 您的代码并查看方法列表,您会发现它是空的。装饰器将在定义而不是实例初始化时装饰方法。看到这种情况发生的一种方法是在装饰器中放置一些印刷品,并且 运行 仅 class 定义。
为了实现您想要的效果,一种方法是使用 class 变量作为方法注册表并稍微更改装饰器:
def filtermethod(registry):
def inner(f):
registry.append(f)
def wrapped(*args, **kwargs):
return f(*args, **kwargs)
return wrapped
return inner
class foo:
methods = []
def apply_filter(self, x):
for fun in foo.methods:
x = fun(self, x)
return x
class foo2(foo):
@filtermethod(foo.methods)
def method1(self, x):
return [i for i in x if i > 5]
@filtermethod(foo.methods)
def method2(self, x):
return [i for i in x if i < 18]
请注意 self
在 apply_filter
方法中作为参数传递。
当你运行:
foo2().apply_filter([1, 4, 1, 5, 73, 25, 7, 2, 26, 13, 46, 9])
您将获得:
[7, 13, 9]
我想创建一个class继承到别处,用装饰器把具体的方法存放在一个属性中
我尝试了以下装饰器
def filtermethod(f):
def wrapped(self, *args, **kwargs):
self.methods.append(f)
return f(self, *args, **kwargs)
return wrapped
并用
定义classesclass foo:
def __init__(self):
self.methods = []
def apply_filter(self, x):
for fun in self.methods:
x = fun(x)
return x
class foo2(foo):
@filtermethod
def method1(self, x):
return [i for i in x if i > 5]
@filtermethod
def method2(self, x):
return [i for i in x if i < 18]
并使用以下
测试classfoo2().apply_filter([1, 4, 1, 5, 73, 25, 7, 2, 26, 13, 46, 9])
并希望所有装饰函数都应用到参数,但我明白了
[1, 4, 1, 5, 73, 25, 7, 2, 26, 13, 46, 9]
而不是
[7,13,9]
基本上,我想将每个用 @filtermethod
修饰的函数附加到属性 self.methods
,(与 self.apply_filter
连续应用) 但我根本做不到。
有什么线索吗?
filtermethod
本身在创建 class 时被调用。因此,您需要在 class 级别上做一些事情。
下面,我更改了您的代码以展示其工作原理。我所做的就是让装饰器用一个变量标记它包装的函数,__init_subclass__
获取并添加到 _methods
(作为未绑定方法)。
def filtermethod(f):
f._is_filter_method = True
return f
class foo:
def __init_subclass__(cls, **kwargs):
funcs = (getattr(cls, v) for v in dir(cls))
cls._methods = [f for f in funcs if hasattr(f, '_is_filter_method')]
def apply_filter(self, x):
for fun in self._methods:
x = fun(self, x)
return x
class foo2(foo):
@filtermethod
def method1(self, x):
return [i for i in x if i > 5]
@filtermethod
def method2(self, x):
return [i for i in x if i < 18]
class foo3(foo2):
@filtermethod
def method1(self, x):
return [i for i in x if i == 4]
编辑:修复了覆盖
如果您 运行 您的代码并查看方法列表,您会发现它是空的。装饰器将在定义而不是实例初始化时装饰方法。看到这种情况发生的一种方法是在装饰器中放置一些印刷品,并且 运行 仅 class 定义。
为了实现您想要的效果,一种方法是使用 class 变量作为方法注册表并稍微更改装饰器:
def filtermethod(registry):
def inner(f):
registry.append(f)
def wrapped(*args, **kwargs):
return f(*args, **kwargs)
return wrapped
return inner
class foo:
methods = []
def apply_filter(self, x):
for fun in foo.methods:
x = fun(self, x)
return x
class foo2(foo):
@filtermethod(foo.methods)
def method1(self, x):
return [i for i in x if i > 5]
@filtermethod(foo.methods)
def method2(self, x):
return [i for i in x if i < 18]
请注意 self
在 apply_filter
方法中作为参数传递。
当你运行:
foo2().apply_filter([1, 4, 1, 5, 73, 25, 7, 2, 26, 13, 46, 9])
您将获得:
[7, 13, 9]