<p>在你编辑之后,我觉得这好像你在寻找一种可能性,把某些事件路由到某些函数,对吧?你知道吗</p>
<p>与其将新属性绑定到现有的<em>实例方法</em>,不如考虑建立一个干净的、可扩展的事件路由系统。你知道吗</p>
<h2>基本路由核心</h2>
<p>虽然通常应用<code>singleton</code>模式总是一个很好的点来问自己是否遵循了正确的概念,但在这里它是完全有意义的。路由的核心与此类似:</p>
<pre><code>def singleton(cls):
instance = cls()
instance.__call__ = lambda: instance
return instance
@singleton
class EventRouter(object):
def __init__(self):
self._routes = dict()
def bind(self, key, func):
self._routes[key] = func
def route(self, key):
if key in self._routes.keys():
return self._routes[key]()
else:
raise KeyError('Unbound routing key: {}'.format(key))
</code></pre>
<p><code>EventRouter</code>是一个单例类,它可以将函数绑定到某些键,并且还可以将发生的事件路由到它们所需的目标函数。<br/>
现在可以在运行时将事件绑定到所需函数:</p>
<pre><code>def my_event_function():
print('An event was handled.')
EventRouter.bind('E_MYEVT', my_event_function)
# If you are iterating over events (for example drawn from a file),
# you can direct them to their functions:
for e in ['E_MYEVT', 'E_WHATEVT', 'E_NOEVT']:
EventRouter.route(e)
</code></pre>
<h2>路由装饰器</h2>
<p>如果需要,可以设置另一个装饰器,用于将方法直接绑定到特定事件类型:</p>
<pre><code>def eventroute(key):
def register_method(call):
EventRouter.bind(key, call)
return register_method
@eventroute('E_MYEVT')
def handle_myevt():
print('Handling event: E_MYEVT')
@eventroute('E_WHATEVT')
def handle_whatevt():
print('Handling event: E_WHATEVT')
if __name__ == '__main__':
for e in ['E_MYEVT', 'E_WHATEVT']:
EventRouter.route(e)
>>> Handling event: E_MYEVT
>>> Handling event: E_WHATEVT
</code></pre>
<h2>向路由端点传递参数</h2>
<p>如果要将参数传递给端点,只需在转发调用时通过可选的关键字参数<code>**kwargs</code>扩展调用:</p>
<p>在<code>EventRouter</code>类中,将<code>route</code>方法更改为:</p>
<pre><code>def route(self, key, **kwargs):
if key in self._routes.keys():
return self._routes[key](**kwargs)
else:
raise KeyError('Unbound routing key: {}'.format(key))
</code></pre>
<p>对于端点,设置所需的参数。在本例中,我使用参数<code>filename</code>:</p>
<pre><code>@eventroute(...)
def handle_...(filename):
print('Handling event: ...')
print(filename)
</code></pre>
<p>在分派事件时,请提供所需的参数kwarg:</p>
<pre><code>events = ['E_MYEVT', 'E_WHATEVT']
for e in events:
EventRouter.route(e, filename='whatever.jpg')
>>> Handling event: E_MYEVT
>>> whatever.jpg
>>> Handling event: E_WHATEVT
>>> whatever.jpg
</code></pre>
<h2>去哪里</h2>
<p>这只是一个非常基本的设置的简要概述。<br/>
您可以将<code>EventRouter</code>扩展为任意复杂,例如,在多层层次结构中添加路由密钥,等等。此外,还可以向方法中添加更多参数。您甚至可以考虑扩展<code>eventroute</code>修饰符来定义传递给端点函数的<code>kwargs</code>,以使函数签名尽可能通用。你知道吗</p>
<p>可能看起来有点过分,但这样的结构非常简洁,任何导入您的库/脚本并希望为单个事件添加自己的端点的人都可以对其进行扩展。你知道吗</p>