使用事件处理程序调用属性设置器



我使用以下类来定义事件:

class Event(object):
    def __init__(self):
        self.handlers = set()
    def handle(self, handler):
        self.handlers.add(handler)
        return self
    def unhandle(self, handler):
        try:
            self.handlers.remove(handler)
        except:
            raise ValueError("Handler is not handling this event, so cannot unhandle it.")
        return self
    def fire(self, *args, **kwargs):
        for handler in self.handlers:
            print(handler)
            handler(*args, **kwargs)
    def getHandlerCount(self):
        return len(self.handlers)
    __iadd__ = handle
    __isub__ = unhandle
    __call__ = fire
    __len__  = getHandlerCount

我有一些像这样定义的模型类:

class SomeModel(object):
    def __init__(self):
        self._foo = 0
        self.fooChanged = Event()
    @property
    def foo(self):
        return self._foo
    @foo.setter
    def foo(self, value):
        self._foo = value
        self.fooChanged(value)

现在,假设我想这样更改foo

model = SomeModel()
other_model = SomeModel()
model.fooChanged += other_model.foo
model.foo = 1

model.foo = 1之后,我会得到以下错误:

typeerror:'int'对象不是可呼叫

现在,假设我使用此代码来定义模型:

class SomeModel(object):
    def __init__(self):
        self._foo = 0
        self.fooChanged = Event()
    def get_foo(self):
        return self._foo
    def set_foo(self, value):
        self._foo = value
        self.fooChanged(value)
    foo = property(get_foo, set_foo)

和此代码更改foo的值:

model = SomeModel()
other_model = SomeModel()
model.fooChanged += other_model.set_foo
model.foo = 1

第二版效果很好,但是,对我来说似乎没有任何意义。我必须定义get_foo方法,我想避免使用该方法(因为属性可用)。这里还有其他解决方法,因此可以运行的第一个版本的代码?

注意:错误将取决于self._foo类型。如果是None,它将返回错误,说明NoneType是不可呼应的,如果是字符串,则错误将声明str对象无法调用。

经过大量挖掘,我发现这个答案非常有用,它朝着正确的方向推动了我。

使用这些知识,我能够通过使用:

来解决此问题
model.fooChanged += lambda value: type(other_model).foo.__set__(other_model, value)

model.fooChanged += lambda value: type(other_model).foo.fset(other_model, value)

后来的线对我来说看起来更加蓬松,因为没有呼叫双输入函数。

在您编写model.fooChanged += other_model.foo时,我想您实际想要的是其Setter方法,但是由于other_model.foo是属性对象,您必须从其类other_model.__class__.foo.fset获得,并写为:

model.fooChanged += lambda value: other_model.__class__.foo.fset(other_model, value)

otoh,我认为您的第二版对我来说是Pythonic,as

显式比隐式更好。

相关内容

  • 没有找到相关文章

最新更新