我正在创建一个具有键盘事件的游戏,以及可以注册功能的事件系统,并且需要返回两个列表(任意大小):游戏时间事件列表和列表实时事件(按此顺序)然后,赛事选手将
我正在重构代码以执行此操作。在之前的系统中,事件会手动将其事件与主游戏时间/实时事件队列合并。
我正在尝试重构在按下/释放键时触发所有事件的代码。目前的代码:
class KeyReleaseEventRunner
GameEvents = []
RealEvents = []
def __call__(self):
"""Run all relevant events."""
# Run key-specific key release events
KeyReleaseEvent[self.key]()
# Run key-specific key toggle events
KeyToggleEvent[self.key](False)
# Run generic key release events
KeyReleaseEvent(self.key)
# Run generic key toggle events
KeyToggleEvent(self.key, False)
我的问题是如何合并这些函数中的所有事件。
是否有更简单易读的方法?
def __call__(self):
"""Run all relevant events."""
# Run key-specific key release events
g_events, r_events = KeyReleaseEvent[self.key]()
self.GameEvents.extend(g_events)
self.RealEvents.extend(r_events)
# Run key-specific key toggle events
g_events, r_events = KeyToggleEvent[self.key](False)
self.GameEvents.extend(g_events)
self.RealEvents.extend(r_events)
# Run generic key release events
g_events, r_events = KeyReleaseEvent(self.key)
self.GameEvents.extend(g_events)
self.RealEvents.extend(r_events)
# Run generic key toggle events
g_events, r_events = KeyToggleEvent(self.key, False)
self.GameEvents.extend(g_events)
self.RealEvents.extend(r_events)
# Events must maintain sorted-ness
self.GameEvents.sort()
self.RealEvents.sort()
我不想在KeyReleaseEventRunner上创建一个方法(这种情况在其他几个地方,并且经常使用局部变量而不是GameEvents / RealEvents)。
更一般地说,让这些函数返回两个列表是否有更好的解决方案?
可以区分g_events和r_events中的事件。
修改
清除有关可调用和可索引的对象的任何混淆:
值得注意的是Event
的实例是注册函数的接口,并且在调用时,调用所有已注册的对象。 KeyToggleEvent
和KeyReleaseEvent
(以及KeyPressEvent
)是Event
的子类的实例,其他模块可以通过其注册特定于键的事件(通过注册到KeyReleaseEvent[key]
})和非关键特定事件(通过注册到KeyReleaseEvent
)。
答案 0 :(得分:2)
我想知道索引和调用的组合是因为它似乎使您的界面过于复杂。这可能不是你想听到的,但我不禁觉得你最好不要使用关键字参数而不是索引来指定事件子集。然后,您可以创建参数列表和对象列表,并迭代它们。像这样:
arg_list = [{'key':self.key, 'foo':False}, {'key':self.key}, ... ]
handlers = [KeyReleaseEvent, KeyToggleEvent, ...]
for handler, args in zip(arg_list, handlers):
g_events, r_events = handler(*args)
self.GameEvents.extend(g_events)
self.RealEvents.extend(r_events)
self.GameEvents.sort()
self.RealEvents.sort()
或者更简洁:
gevents_revents = [handler(*args) for handler, args in zip(arg_list, handlers)]
all_gevents, all_revents = zip(*gevents_revents)
self.GameEvents.extend(e for sublist in all_gevents for e in sublist)
self.RealEvents.extend(e for sublist in all_revents for e in sublist)
当然,您可以使用当前的设置执行此类操作。但我担心,它会有点不那么优雅。
我还认为您应该考虑为事件队列使用不同的数据结构。您是否考虑使用优先级队列而不是简单列表,例如heapq
提供的优先级队列?这将允许您避免重复(O(n log n))排序。单个插入和删除将是O(log n),这比使用列表(O(n))的朴素方法更好,但比更仔细的方法(O(1))更糟。实际上,随着时间的推移,您将分散工作,因为单个项目将从队列中删除,而不是一次性完成所有操作。但你仍然会得到O(n)合并!
这是否正确的方法取决于你自己的情况。 (例如,如果您需要查看将来事件的顺序,这不是最好的方法。)如果您感兴趣,我可以写更多关于此的内容,但基本的想法是您可以使用{{1 (O(n))而不是heapq.heapify
(O(n log n))。
sort
然后从队列中获取最高优先级的项目:
arg_list = [{'key':self.key, 'foo':False}, {'key':self.key}, ... ]
handlers = [KeyReleaseEvent, KeyToggleEvent, ...]
for handler, args in zip(arg_list, handlers):
g_events, r_events = handler(*args)
self.GameEvents.extend(g_events)
self.RealEvents.extend(r_events)
heapq.heapify(self.GameEvents)
heapq.heapify(self.RealEvents)