我使用以下类来定义事件:
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>
答案 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.foo
是property object,你必须从它的类other_model.__class__.foo.fset
获得,写作:
model.fooChanged += lambda value: other_model.__class__.foo.fset(other_model, value)
OTOH,我认为你的第二个版本对我来说是pythonic,因为:
明确比隐含更好。