python 中的惰性事件发布订阅
我的谷歌应用程序引擎应用程序中需要一个事件消息系统。
我指的是以下 python 库。
http://pubsub.sourceforge.net/apidocs/concepts.html
我的问题是,我想要执行的侦听器函数是否必须导入(或以其他方式存在)到执行路径中的某个位置才能在事件上运行它?
有很多很多的事件,我想让它尽可能地延迟加载。
有什么解决方法吗?
python 中是否有惰性事件发布订阅框架?
I need an event messaging system in my google app engine application.
and i was referring to following python library.
http://pubsub.sourceforge.net/apidocs/concepts.html
my question is , is it must that the listener function i want to execute must be imported ( or exist otherwise) somewhere in to the execution path in order to run it on event ?
There are many lots of event, and I want to make it as lazy loaded as possible.
what could be the work around ?
is there any lazy event publish subscribe framework in python ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
tipfy(App-Engine 特定的微框架)具有延迟加载功能,但仅适用于特定的“事件”您的代码正在服务的网络请求。其他 Web 框架也有它,但 Tipfy 足够小且简单,可以轻松地研究和模仿其源代码。
因此,如果由于“延迟加载”问题而找不到完全符合您口味的更丰富的事件框架,您可以选择一个需要注册/订阅可调用对象并允许字符串命名的框架函数也可以被注册,就像tipfy一样。当然,如果需要为某些事件提供服务,则可以及时加载如此命名的函数。
让我用一些简化的假设代码来举例说明。假设您有一个事件框架,其中包括以下内容:
当然,任何现实世界事件框架的内部都会更丰富,但类似的内容将在其最低层中被识别。
因此,这需要在注册时加载可调用对象......但是,即使不触及框架的内部结构,您也可以轻松扩展它。考虑一下:
当然,您需要更好的错误处理 &c,但这就是它的要点:将命名函数的字符串(例如
'package.module.func'
)包装到包装器中知道如何延迟加载它的对象。现在,register(LazyCall('package.module.func'))
将在未受影响的框架中注册这样一个包装器,并根据请求延迟加载它。顺便说一句,这个用例可以用作 Python 习语的一个相当好的例子,一些顽固的傻瓜大声而刺耳地声称不存在或不应该存在,或者其他什么:动态改变自己的类的对象。该习惯用法的用例是为存在于两种状态之一的对象“切断中间人”,从第一种状态到第二种状态的转换是不可逆的。在这里,惰性调用者的第一个状态是“我知道函数的名称但没有对象”,第二个状态是“我知道函数对象”。由于从第一个移动到第二个是不可逆的,因此您可以减少每次测试的小开销(或
Strategy
设计模式的间接开销),如果您愿意的话:这里的增益是适度的,因为它基本上只是从每次调用中删除一个
if self.f is None:
检查;但这是一个真正的收获,没有真正的缺点,除了导致之前提到的顽固的傻瓜陷入他们典型的愤怒和盲目的疯狂(如果你把那算作一个缺点的话)。不管怎样,实施的选择取决于你,而不是我——或者,幸运的是,你的选择取决于他们;-)。
一种设计选择是:是否修补
register
本身以直接接受字符串参数(并根据需要包装它们),基本上就像tipfy
所做的那样,或者进行显式包装注册站点,保持register
(或subscribe
或无论如何称呼)原始状态。在这种特殊情况下,我并没有对“显式优于隐式”的口头禅给予太多重视,因为类似的东西非常明确
,即它很非常清楚发生了什么,并且可以说是更干净/更具可读性。
尽管如此,显式包装方法使底层框架保持不变,这确实很好:无论您在哪里可以传递函数,现在都可以传递该函数的名称(作为字符串命名包、模块和函数本身),无缝地。因此,如果我改造现有框架,我会采用显式方法。
最后,如果您想注册不是函数而是(例如)某些类的实例或此类实例的绑定方法的可调用对象,您可以将
LazyCall
丰富为LazyInstantiateAndCall
等变体。 code> &c 就是为了这个目的。当然,架构会变得更加复杂(例如,因为您需要实例化新对象的方法和识别已经存在的对象的方法),但是通过将这项工作委托给设计良好的工厂系统,应该不会太糟糕。然而,我没有更深入地进行此类改进,因为这个答案已经相当长了,无论如何,在许多情况下,简单的“命名函数”方法就足够了!-)tipfy (an App-Engine specific micro framework) has lazy loading, but only for the specific "events" that are web requests your code is serving. Other web frameworks have it too, but tipfy is small and simple enough to easily study and imitate its sources for the purpose.
So, if you can't find a richer event framework that's exactly to your taste because of the "lazy loading" issue, you could pick one which requires registration/subscription of callable objects, and allow strings naming functions to be registered as well, just as tipfy does. The function thus named, of course, would be loaded just in time if an when needed to serve some event.
Let me exemplify with some simplified, hypothetical code. Say that you have an event framework that includes something like:
The internals of any real-world event framework will be richer, of course, but something like this will be discernible at the lowest layers of it.
So, this requires the callable to be loaded at registration time... and yet, even without touching the internals of your framework, you can easily extend it. Consider:
You'll want better error handling &c, of course, but this is the gist of it: wrap the string naming the function (e.g.
'package.module.func'
) into a wrapper object that knows how to lazily load it. Now,register(LazyCall('package.module.func'))
will register, in the untouched framework, such a wrapper -- and lazy-load it on request.This use case, btw, could be used as a reasonably good example of a Python idiom that some obstreperous fools claim, loudly and stridently, doesn't exist, or shouldn't exist, or something: an object dynamically changing its own class. Use cases for this idiom are to "cut the middleman" for objects that exist in one of two states, with the transition from the first to the second being irreversible. Here, the first state of a lazy caller is "I know the function's name but don't have the object", the second one is "I know the function object". Since moving from the first to the second is irreversible, you can cut the small overhead of testing every time (or the indirection overhead of the
Strategy
design pattern), if you wish:The gain here is modest, as it basically just cuts one
if self.f is None:
check from each call; but it's a real gain, without real downsides except for causing the previously named obstreperous fools to flail into their typical angry and mindless frenzy (if you count that as a downside).Anyway, the implementation choice is up to you, not to me -- or, lucky you, to them;-).
As is one design choice: whether to patch
register
itself to directly accept string arguments (and wrap them as needed), basically astipfy
does, or go for the explicit wrapping at the registration site, leavingregister
(orsubscribe
or however it's called) pristine. I don't set much weight by the "explicit is better than implicit" mantra in this particular case, since something likeis quite as explicit as
i.e., it is quite clear what's going on, and it's arguably cleaner / more readable.
Nevertheless, it is really nice that the explicit wrapping approach leaves the underlying framework untouched: wherever you could pass a function, you can now pass the name of that function (as a string naming packages, module, and the function itself), seamlessly. So, were I retrofitting existing frameworks, I'd go for the explicit approach.
Finally, if you want to register callables that are not functions but (for example) instances of certain classes, or bound methods of such instances, you can enrich
LazyCall
into variants such asLazyInstantiateAndCall
&c for the purpose. The architecture becomes a tad more complex, of course (since you want ways to instantiate new objects and ways to identify already existing ones, for example), but by delegating that work to a well designed system of factories, it shouldn't be too bad. However, I'm not getting any deeper in such refinements, since this answer is already rather long, and anyway, in many cases, the simple "name a function" approach should suffice!-)