我正在创建一个事件系统,它将以下类用于事件:
class Event(set):
def __init__(self, name, iterable=()):
super().__init__(iterable)
self.name = name
def __iadd__(self, listener):
self.add(listener)
return self
def __isub__(self, listener):
self.remove(listener)
return self
def fire(self, **eargs):
for listener in self:
listener(**eargs)
现在我正在尝试创建某种类型的dict,它会自动在__init__
中创建事件,如下所示:
class EventDict(dict):
def __init__(self, prefix, *event_names):
super().__init__({
name: Event('%s.%s' % (prefix, name))
for name in event_names
})
以下是一个使用示例:
class Player:
def __init__(self, name):
self._name = name
self.events = EventDict('Player', 'change_name')
@property
def name(self):
returns self._name
@name.setter
def name(self, value):
old_name = self.name
self.name = value
self.events['change_name'].fire(player=self, old_name=old_name)
现在我面临的问题是子类化。
如果我将我的Player
类子类化为包含health
属性,我不能使用相同的方式创建事件dict,因为它会覆盖现有的dict而我无法访问{ {1}}。
所以我试图找到一种方法,我可以做这样的事情(理想的解决方案):
change_name
这样的事情会成为可能吗?
我知道我能做到:
class Player:
events = EventDict('Player', 'change_name')
class Player2(Player):
events = EventDict('Player2', 'attack', 'kill')
p2 = Player2()
p2.events['change_name'] += my_event_listener # Still access Player class's events
但它不一样:P
答案 0 :(得分:1)
我认为你想要的是:
class Player:
EVENTS = ('change_name',)
def __init__(self, name):
self._name = name
self.events = EventDict(
self.__class__.__name__,
*self.EVENTS,
)
...
然后Player2
所需要的只是:
class Player2(Player):
EVENTS = Player.EVENTS + ('attack', 'kill')
并且继承的__init__
可以正常工作。
答案 1 :(得分:0)
停止使用EventDict
。
该类本身有自己的dict,支持这样的继承。
class Player:
def __init__(self, name):
self._name = name
self.change_name_event = Event('Player.change_name')
class Player2(Player):
def __init__(self, name):
super().__init__(name)
self.attack_event = Event('Player2.attack')
self.kill_event = Event('Player2.kill')
无论如何,都会添加子类中的所有事件。
我注意到,也许你想明确表示他们是事件,所以我在字段的名称中添加了“event”,但如果你不想这样做,则不需要。
如果你想要它以使前缀始终相同,那么你就可以将字符串从'Player.change_name'
更改为self.__class__.__name__ + '.change_name'
。这样,它总是得到对象的实际类。这是@ jonrsharpe解决方案试图获得的一部分。
如果你想让别人可以动态添加更多事件,他们可以简单地执行像playerObj.my_new_event = Event('Player.my_new_event')
或这样的行,你可以在Player
中提供一个不错的方法让他们的生活更轻松的课程:
def add_event(self, event_name):
setattr(self, event_name, Event(self.__class__.__name__ + '.' + event_name)