<p>还有一些方法。。。</p>
<h3>示例:日志模块</h3>
<p>也许您只需要从stderr切换到Python的<a href="http://docs.python.org/library/logging.html#datagramhandler" rel="noreferrer">^{<cd1>}</a>模块,该模块具有强大的发布/订阅模型。</p>
<p>很容易开始制作日志记录。</p>
<pre><code># producer
import logging
log = logging.getLogger("myjobs") # that's all the setup you need
class MyJob(object):
def run(self):
log.info("starting job")
n = 10
for i in range(n):
log.info("%.1f%% done" % (100.0 * i / n))
log.info("work complete")
</code></pre>
<p>在消费者方面,还有更多的工作要做。不幸的是,配置记录器输出需要大约7行代码。;)</p>
<pre><code># consumer
import myjobs, sys, logging
if user_wants_log_output:
ch = logging.StreamHandler(sys.stderr)
ch.setLevel(logging.INFO)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
myjobs.log.addHandler(ch)
myjobs.log.setLevel(logging.INFO)
myjobs.MyJob().run()
</code></pre>
<p>另一方面,日志包中有大量的内容。如果您需要将日志数据发送到一组旋转的文件、电子邮件地址和Windows事件日志,我们将为您提供帮助。</p>
<h3>示例:最简单的可能观察者</h3>
<p>但你根本不需要使用任何库。支持观察者的一个非常简单的方法是调用一个什么也不做的方法。</p>
<pre><code># producer
class MyJob(object):
def on_progress(self, pct):
"""Called when progress is made. pct is the percent complete.
By default this does nothing. The user may override this method
or even just assign to it."""
pass
def run(self):
n = 10
for i in range(n):
self.on_progress(100.0 * i / n)
self.on_progress(100.0)
# consumer
import sys, myjobs
job = myjobs.MyJob()
job.on_progress = lambda pct: sys.stdout.write("%.1f%% done\n" % pct)
job.run()
</code></pre>
<p>有时候你可以说<code>job.on_progress = progressBar.update</code>,而不是写一个lambda,这很好。</p>
<p>这很简单。一个缺点是它不能自然地支持订阅同一事件的多个侦听器。</p>
<h3>示例:类C事件</h3>
<p>通过一些支持代码,您可以在Python中获得类似C#的事件。代码如下:</p>
<pre><code># glue code
class event(object):
def __init__(self, func):
self.__doc__ = func.__doc__
self._key = ' ' + func.__name__
def __get__(self, obj, cls):
try:
return obj.__dict__[self._key]
except KeyError, exc:
be = obj.__dict__[self._key] = boundevent()
return be
class boundevent(object):
def __init__(self):
self._fns = []
def __iadd__(self, fn):
self._fns.append(fn)
return self
def __isub__(self, fn):
self._fns.remove(fn)
return self
def __call__(self, *args, **kwargs):
for f in self._fns[:]:
f(*args, **kwargs)
</code></pre>
<p>生产者使用decorator声明事件:</p>
<pre><code># producer
class MyJob(object):
@event
def progress(pct):
"""Called when progress is made. pct is the percent complete."""
def run(self):
n = 10
for i in range(n+1):
self.progress(100.0 * i / n)
#consumer
import sys, myjobs
job = myjobs.MyJob()
job.progress += lambda pct: sys.stdout.write("%.1f%% done\n" % pct)
job.run()
</code></pre>
<p>它的工作方式与上面的“简单观察者”代码完全相同,但是您可以使用<code>+=</code>添加任意数量的侦听器。(与C不同,这里没有事件处理程序类型,订阅事件时不必<code>new EventHandler(foo.bar)</code>,也不必在触发事件之前检查null。与C#一样,事件不会压制异常。)</p>
<h3>如何选择</h3>
<p>如果<code>logging</code>做了您需要的一切,那么就使用它。否则就做最简单的事情。需要注意的关键是,您不需要承担很大的外部依赖性。</p>