使用事件手调用属性设置器

2024-04-23 21:54:51 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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' object is not callable

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

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

第二个版本的作品很好,但它似乎有点不Python我。我必须定义get_foo方法,这是我想要避免的(因为属性是可用的)。这里是否有其他解决方法,以便可以运行第一个版本的代码?你知道吗

注意:错误取决于self._foo类型。如果是None,则返回错误,指出NoneType不可调用;如果是字符串,则返回错误,指出str对象不可调用。你知道吗


Tags: selfmodelreturn定义objectfoovaluehandlers
2条回答

经过大量的挖掘,我发现这个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)

后一行在我看来更像python,因为没有调用双下划线函数。你知道吗

当您编写model.fooChanged += other_model.foo时,我想您实际上想要的是它的setter方法,但是由于other_model.foo是一个property object,您必须从它的类other_model.__class__.foo.fset中获取,编写为:

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

奥托,我觉得你的第二个版本对我来说很像Python,比如:

Explicit is better than implicit.

相关问题 更多 >