ベストアンサー
上記のコメントに基づいて、ここに「一般的な戦略」を示します。もちろん、詳細は非常に重要です。 。
基本的には2つの部分があります。
イベントオブジェクトまたは「発行者」が責任を負いますイベントが発生したときに呼び出す必要があるすべての関数のリストを維持します。 fire()
メソッドがあり、そのリストをループしてすべての関数を順番に呼び出します。おそらく、リストを管理するためのメソッドも必要です(リストから関数を削除する必要はありません)。
ハンドラーまたは「サブスクライバー」は、イベントが実際に発生したときに呼び出す関数です。唯一注意が必要なのは、ハンドラーの署名を制御して、イベントが追加のイントロスペクションを行わずにハンドラーを呼び出すことができるようにする必要があることです。
これは非常に最小限の例です:
class Event(object):
def \_\_init\_\_(self, *args):
self.handlers = set()
self.args = args
def add(self, fn):
self.handlers.add(fn)
def remove(self, fn):
self.handlers.remove(fn)
def \_\_call\_\_(self, *args):
"""fire the event -- uses \_\_call\_\_ so we can just invoke the object directly..."""
runtime\_args = self.args + args
for each\_handler in self.handlers:
each\_handler(*runtime\_args)
class ExampleObject(object):
"""publish start and stop events"""
def \_\_init\_\_(self):
self.start = Event("started")
self.stop = Event("stopped")
def example\_handler(*args):
""" reacts to an event"""
print "example handler fired", args
fred = ExampleObject()
fred.start.add(example\_handler)
fred.stop.add(example\_handler)
fred.start()
fred.stop("optional extra arg")
生成されるはずです
example handler fired ("started",)
example handler fired ("stopped", "optional extra arg")
主な管理上の問題は次のとおりです。
例外処理。 ハンドラーを例外安全にする必要があるかどうかを判断する必要があります。上記のコードが多かれ少なかれ問題ない場合でも、悪いサブスクライバーがプログラム全体を停止させたくない場合は、例外に対処する方法と、問題のあるハンドラーを「サブスクライブ解除」するかどうかを決定する必要があります。 。
メモリ管理。この例では、関数をハンドラーとしてのみ使用しています。関数をdel()しない限り、必要はありません。ライフタイムを管理します。ただし、多くの場合、呼び出し可能なオブジェクトまたはメンバー関数のいずれかをハンドラー/サブスクライバーとして使用する必要があります。その場合、例で使用されているナイーブセットではなく、弱参照を使用する必要があります。そうしないと、イベントハンドラーは、オブジェクトがスコープから外れ、ガベージコレクションされるはずだった後、オブジェクトを存続させてしまいます。
メタデータ:この例には、メタデータが少し含まれています。これは、Event()
が宣言されます。アプリケーションには、これより多いまたは少ない必要がある場合があります。通常、メタデータが多いほど結合が多くなりますが、これは理想的ではありません。ただし、ハンドラーがすべて(*args, **kwargs)
署名を持っている場合は、いつでもデータを渡して、それを気にするかどうかをハンドラーレベルで決定できます。
参考資料: Pythonのオブザーバーパターン
実際の基本的な考え方の例: theodox / mGui
回答
トルネードWebフレームワークのWebサイトにアクセスすると、サンプルページがあります。そのページには、チャットアプリケーションコードの例があります。短くて理解しやすいです。