事件驱动编程库
dispatcher的Python项目详细描述
#dispatch:signal broadcasting in python
此python库是从[django](http://djangoproject.com)的[dispatch模块](http://code.djangoproject.com/browser/django/trunk/django/dispatch)中提取的。
信号](http://docs.djangoproject.com/en/1.1/topics/signals/)。
overview
==
当两段互不相关的代码相互依赖时,信号很有用。
一般模式是,*接收器*(或侦听器)可以*订阅(或侦听)的*信号*。a*sender*
当发送方发送(或广播)信号时,调用接收器。
*发送者不需要知道
*"谁"获取消息,
*侦听器将如何处理数据,
*甚至*如果*任何侦听器都将获取消息数据;
*类似地,监听器不必担心消息从何而来。
lazy evaluation pattern
——当涉及到任何昂贵的计算时都非常有用。
假设一些昂贵的函数"f"依赖于一个变量"x"。
因为函数的计算是昂贵的,值"f(x)"将被缓存。
一种天真的方法是让"x"(或负责它的对象)显式地告诉函数"f"x已更改。
缺点是"x"必须知道依赖它的所有函数!
这使得代码很难重用,由于每次添加依赖于"x"的函数时,都必须更改负责"x"的代码。
这是不可接受的。
然后,函数"f"监听该信号,并将其缓存值设置为需要重新计算。
后一种方法非常灵活。
它允许多个函数依赖于一个变量"x",在变量"x"不知道的情况下。
它还允许一个函数依赖多个变量,只要所有这些变量在其值更改时发送信号。
定义和发送信号
信号将提供给侦听器的参数名称。
例如:
`` python
import dispatch
pizza\u done=dispatch.signal(提供参数=["toppings","size"])
```
因此,在第一次尝试时正确使用api是不必要的。
下面是发送"pizza完成"信号的方式:
``python
class pizza store(object):
…
def send_pizza(self,toppings,size):
pizza完成。send(sender=self,toppings=toppings,size=size)
…
```
y注册一个在每个比萨饼完成后调用的信号。
我们将连接到"比萨饼完成"信号。
我们需要定义一个接收器函数。
接收器可以是任何python函数或方法:
``python
def my_callback(sender,**kwargs):
print"pizza ready!"
``
请注意,该函数接受一个"sender"参数,以及通配符关键字参数(`**kwargs`);
所有信号处理程序都必须接受这些参数。
并且可以随时更改这些关键字参数。
在"pizza_done"的情况下,它记录为发送两个参数,topping和size,这意味着我们可能会尝试将信号处理编写为"my_callback(sender,topping s,size)"。
` dispatch`如果这样做,将抛出一个错误。
这是因为在任何时候都可以向信号添加参数,而您的接收器必须能够处理这些新参数。
我们需要将接收器连接到信号:
``python
pizza完成。现在连接(我的回调)
```
,每次披萨准备好时,我们的"My_Callback"函数都会被调用。
连接到特定发件人发送的信号
但你只会对接收这些信号的某一子集感兴趣。
例如,考虑"比萨饼完成"信号。
大多数情况下,你不需要知道什么时候*任何*比萨饼都准备好了,就在*某个*比萨饼商店的比萨饼准备好了的时候。
您可以注册以接收仅由特定发件人发送的信号。
在比萨饼示例中,发件人将是比萨饼店,因此您可以指示您只希望
由一种特定比萨饼店发送的信号,或者某个比萨店:
`` python
类素食比萨店(pizza store):
…
def my_handler(sender,**kwargs):
…
pizza done.connect(my_handler,sender=素食比萨店)
``
只有当任何"素食披萨店"的披萨都准备好了。
类似地,您可能只对在一家特定披萨店准备的披萨感兴趣:
``python
my砦pizza砦store=pizzastore()
…
def my砦handler(发件人,**kwargs):
…
pizza完成。connect(my_handler,sender=my_pizza廑store)
```
my廑handler`函数仅在对象my廑pizza廑store'中的披萨准备就绪时调用。
此python库是从[django](http://djangoproject.com)的[dispatch模块](http://code.djangoproject.com/browser/django/trunk/django/dispatch)中提取的。
信号](http://docs.djangoproject.com/en/1.1/topics/signals/)。
overview
==
当两段互不相关的代码相互依赖时,信号很有用。
一般模式是,*接收器*(或侦听器)可以*订阅(或侦听)的*信号*。a*sender*
当发送方发送(或广播)信号时,调用接收器。
*发送者不需要知道
*"谁"获取消息,
*侦听器将如何处理数据,
*甚至*如果*任何侦听器都将获取消息数据;
*类似地,监听器不必担心消息从何而来。
lazy evaluation pattern
——当涉及到任何昂贵的计算时都非常有用。
假设一些昂贵的函数"f"依赖于一个变量"x"。
因为函数的计算是昂贵的,值"f(x)"将被缓存。
一种天真的方法是让"x"(或负责它的对象)显式地告诉函数"f"x已更改。
缺点是"x"必须知道依赖它的所有函数!
这使得代码很难重用,由于每次添加依赖于"x"的函数时,都必须更改负责"x"的代码。
这是不可接受的。
然后,函数"f"监听该信号,并将其缓存值设置为需要重新计算。
后一种方法非常灵活。
它允许多个函数依赖于一个变量"x",在变量"x"不知道的情况下。
它还允许一个函数依赖多个变量,只要所有这些变量在其值更改时发送信号。
定义和发送信号
信号将提供给侦听器的参数名称。
例如:
`` python
import dispatch
pizza\u done=dispatch.signal(提供参数=["toppings","size"])
```
因此,在第一次尝试时正确使用api是不必要的。
下面是发送"pizza完成"信号的方式:
``python
class pizza store(object):
…
def send_pizza(self,toppings,size):
pizza完成。send(sender=self,toppings=toppings,size=size)
…
```
y注册一个在每个比萨饼完成后调用的信号。
我们将连接到"比萨饼完成"信号。
我们需要定义一个接收器函数。
接收器可以是任何python函数或方法:
``python
def my_callback(sender,**kwargs):
print"pizza ready!"
``
请注意,该函数接受一个"sender"参数,以及通配符关键字参数(`**kwargs`);
所有信号处理程序都必须接受这些参数。
并且可以随时更改这些关键字参数。
在"pizza_done"的情况下,它记录为发送两个参数,topping和size,这意味着我们可能会尝试将信号处理编写为"my_callback(sender,topping s,size)"。
` dispatch`如果这样做,将抛出一个错误。
这是因为在任何时候都可以向信号添加参数,而您的接收器必须能够处理这些新参数。
我们需要将接收器连接到信号:
``python
pizza完成。现在连接(我的回调)
```
,每次披萨准备好时,我们的"My_Callback"函数都会被调用。
连接到特定发件人发送的信号
但你只会对接收这些信号的某一子集感兴趣。
例如,考虑"比萨饼完成"信号。
大多数情况下,你不需要知道什么时候*任何*比萨饼都准备好了,就在*某个*比萨饼商店的比萨饼准备好了的时候。
您可以注册以接收仅由特定发件人发送的信号。
在比萨饼示例中,发件人将是比萨饼店,因此您可以指示您只希望
由一种特定比萨饼店发送的信号,或者某个比萨店:
`` python
类素食比萨店(pizza store):
…
def my_handler(sender,**kwargs):
…
pizza done.connect(my_handler,sender=素食比萨店)
``
只有当任何"素食披萨店"的披萨都准备好了。
类似地,您可能只对在一家特定披萨店准备的披萨感兴趣:
``python
my砦pizza砦store=pizzastore()
…
def my砦handler(发件人,**kwargs):
…
pizza完成。connect(my_handler,sender=my_pizza廑store)
```
my廑handler`函数仅在对象my廑pizza廑store'中的披萨准备就绪时调用。