使用事件处理程序调用属性setter

时间:2017-09-30 12:04:41

标签: python event-handling

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

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

第二个版本工作得很好,然而,对我来说它似乎没有什么非Pythonic。我必须定义get_foo方法,我想避免这种方法(因为属性可用)。这里有其他一些解决方法,所以第一版代码可以运行吗?

注意:错误取决于self._foo类型。如果它是None,它将返回错误,指出NoneType不可调用,如果它是字符串,则错误将指出str对象不可调用。< / p>

2 个答案:

答案 0 :(得分:0)

经过大量的挖掘,我发现这个answer非常有用,它让我朝着正确的方向前进。

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

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

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

后面的行对我来说看起来更像Pythonic,因为没有调用双下划线函数。

答案 1 :(得分:0)

当你写model.fooChanged += other_model.foo时,我猜你真正想要的是它的setter方法,但由于other_model.fooproperty object,你必须从它的类other_model.__class__.foo.fset获得,写作:

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

OTOH,我认为你的第二个版本对我来说是pythonic,因为:

  

明确比隐含更好。