Python 用于更改对象状态的装饰器

Python 用于更改对象状态的装饰器,python,class,inheritance,decorator,Python,Class,Inheritance,Decorator,我想创建一个类在别处继承,并使用装饰器在属性中存储特定的方法 我试过下面的装饰师 def filtermethod(f): def wrapped(self, *args, **kwargs): self.methods.append(f) return f(self, *args, **kwargs) return wrapped 并使用 class foo: def __init__(self): self.metho

我想创建一个类在别处继承,并使用装饰器在属性中存储特定的方法

我试过下面的装饰师

def filtermethod(f):
    def wrapped(self, *args, **kwargs):
        self.methods.append(f)
        return f(self, *args, **kwargs)
    return wrapped
并使用

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]
期望所有修饰函数都应用于参数,但我明白了

[1, 4, 1, 5, 73, 25, 7, 2, 26, 13, 46, 9]
而不是

[7,13,9]
基本上,我想将每个用
@filtermethod
修饰的函数附加到属性
self.methods
,(用
self.apply\u filter
连续应用),但我就是做不到


有什么线索吗?

过滤器方法本身在创建类时被调用。因此,你需要在课堂上做一些事情

下面,我更改了您的代码,以显示这是如何工作的。我所做的就是让装饰程序用
\uuu init\u subclass\uu
拾取并添加到
\u方法中的变量标记它要包装的函数(作为未绑定的方法)

def过滤器方法(f):
f、 _是_filter_method=True
返回f
foo类:
定义初始子类(cls,**kwargs):
funcs=(getattr(cls,v)表示目录中的v(cls))
cls._methods=[f表示函数中的f,如果hasattr(f,“_是_filter_method”)]
def应用过滤器(自身,x):
自娱自乐的方法:
x=乐趣(自我,x)
返回x
第二类(foo):
@过滤法
def方法1(自身,x):
返回[如果i>5,则i代表x中的i]
@过滤法
def方法2(自身,x):
返回[如果i<18,则i代表x中的i]
第三类(第二类):
@过滤法
def方法1(自身,x):
返回[i=4时x中i的i]

编辑:已修复重写

过滤器方法
本身在创建类时被调用。因此,你需要在课堂上做一些事情

下面,我更改了您的代码,以显示这是如何工作的。我所做的就是让装饰程序用
\uuu init\u subclass\uu
拾取并添加到
\u方法中的变量标记它要包装的函数(作为未绑定的方法)

def过滤器方法(f):
f、 _是_filter_method=True
返回f
foo类:
定义初始子类(cls,**kwargs):
funcs=(getattr(cls,v)表示目录中的v(cls))
cls._methods=[f表示函数中的f,如果hasattr(f,“_是_filter_method”)]
def应用过滤器(自身,x):
自娱自乐的方法:
x=乐趣(自我,x)
返回x
第二类(foo):
@过滤法
def方法1(自身,x):
返回[如果i>5,则i代表x中的i]
@过滤法
def方法2(自身,x):
返回[如果i<18,则i代表x中的i]
第三类(第二类):
@过滤法
def方法1(自身,x):
返回[i=4时x中i的i]

编辑:修复了覆盖

的问题,如果运行代码并查看方法列表,您会发现它是空的。装饰器将根据定义而不是实例初始化来装饰方法。看到这种情况的一种方法是在decorator中放置一些打印,然后只运行类定义

为了实现您想要的功能,一种方法是使用类变量作为方法注册表,并将装饰器稍微更改为:

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]
您将获得:

[7, 13, 9]

如果运行代码并查看方法列表,您会发现它是空的。装饰器将根据定义而不是实例初始化来装饰方法。看到这种情况的一种方法是在decorator中放置一些打印,然后只运行类定义

为了实现您想要的功能,一种方法是使用类变量作为方法注册表,并将装饰器稍微更改为:

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]
您将获得:

[7, 13, 9]

self.methods
添加包装方法的唯一时间是实际调用包装方法时,例如
method1
method2
。向
self.methods
添加包装方法的唯一时间是实际调用包装方法时,例如
method1
method2
。谢谢。我可以用新的子类
foo3(foo2)
覆盖
method1
吗?用新的类
foo3(foo2)
我无法正确覆盖
method1
method2
变为非活动状态,或者两种方法都不起作用all@mccandar现在就试试吧-修正了上手的问题。我可以用新的子类
foo3(foo2)
覆盖
method1
吗?用新的类
foo3(foo2)
我无法正确覆盖
method1
method2
变为非活动状态,或者两种方法都不起作用all@mccandar现在就试试吧-修好了
[7, 13, 9]