在 super class 的 init 和 subclass 的 init 中自动组合字典?
Combining dict in super class's init and subclass's init automatically?
我正在创建一个事件系统,它使用以下 class 事件:
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)
现在我正在尝试创建某种字典,它会自动在其 __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)
现在我面临的问题是subclassing。
如果我要 subclass 我的 Player
class 也包含 health
属性,我不能使用相同的方式创建事件字典,因为它会覆盖现有的,我无法再访问 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
这样的事情可能吗?
我知道我能做到:
class Player2(Player):
def __init__(self, name):
super().__init__()
self.events.update(...)
但不一样:P
我认为你想要的是:
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__
将正常工作。
停止使用 EventDict
。
class 本身有自己的 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')
无论如何都会添加子class中的所有事件。
我注意到你可能想让它们明显地表明它们是事件,所以我在字段名称中添加了 'event',但如果你不想,则不需要.
如果您希望前缀始终相同,则可以将字符串从 'Player.change_name'
更改为 self.__class__.__name__ + '.change_name'
。这样,它总是得到对象的 actual class 是什么。这是@jonrsharpe 的解决方案试图达到的目的的一部分。
如果你想让其他人可以动态添加更多事件,他们可以简单地做一行 playerObj.my_new_event = Event('Player.my_new_event')
或 你可以在Player
class 让他们的生活更轻松:
def add_event(self, event_name):
setattr(self, event_name, Event(self.__class__.__name__ + '.' + event_name)
我正在创建一个事件系统,它使用以下 class 事件:
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)
现在我正在尝试创建某种字典,它会自动在其 __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)
现在我面临的问题是subclassing。
如果我要 subclass 我的 Player
class 也包含 health
属性,我不能使用相同的方式创建事件字典,因为它会覆盖现有的,我无法再访问 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
这样的事情可能吗?
我知道我能做到:
class Player2(Player):
def __init__(self, name):
super().__init__()
self.events.update(...)
但不一样:P
我认为你想要的是:
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__
将正常工作。
停止使用 EventDict
。
class 本身有自己的 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')
无论如何都会添加子class中的所有事件。
我注意到你可能想让它们明显地表明它们是事件,所以我在字段名称中添加了 'event',但如果你不想,则不需要.
如果您希望前缀始终相同,则可以将字符串从 'Player.change_name'
更改为 self.__class__.__name__ + '.change_name'
。这样,它总是得到对象的 actual class 是什么。这是@jonrsharpe 的解决方案试图达到的目的的一部分。
如果你想让其他人可以动态添加更多事件,他们可以简单地做一行 playerObj.my_new_event = Event('Player.my_new_event')
或 你可以在Player
class 让他们的生活更轻松:
def add_event(self, event_name):
setattr(self, event_name, Event(self.__class__.__name__ + '.' + event_name)