追加の状態とコールバック関数

しばしば遭遇した状況をコードするようなイベントハンドラなどというようにコールバック関数を、記述する必要があります。従来の一般的なコールバック関数として、戻り値が算出、パラメータを渡します。

def apply_async(func, args, *, callback): 
    # Compute the result
    result = func(*args)

    # Invoke the callback with the result
    callback(result)

def print_result(result):
    print('Got:', result)

def add(x, y):
    return x + y

>>> apply_async(add, (2, 3), callback=print_result)
Got: 5
>>> apply_async(add, ('hello', 'world'), callback=print_result)
Got: helloworld
>>>

ノート、print_result()関数は、一つのパラメータのみ、結果を取ります。他の情報転送ません。あなたはコールバック関数と環境との一部または相互作用する他の変数をしたい場合には、情報の不足は時々問題を引き起こします。
コールバックや情報ではなく、単純な機能の結合方法を使用することであるように、余分な状態を運びます。例えば、クラス定義を使用します。次のとおりです。

class ResultHandler:
    def __init__(self):
        self.sequence = 0
    def handler(self, result):
        self.sequence += 1
        print('[{}] Got: {}'.format(self.sequence, result))

>>> r = ResultHandler()
>>> apply_async(add, (2, 3), callback=r.handler)
[1] Got: 5
>>> apply_async(add, ('hello', 'world'), callback=r.handler) 
[2] Got: helloworld
>>>

クラス属性の使用例は、その状態のシーケンスを運ぶ、その状態毎に取得し、コールバックを更新することができます。
クラスのインスタンスを使用せずに、クロージャは道の状態をキャプチャするために使用することができます。次のとおりです。

def make_handler():
    sequence = 0
    def handler(result):
        nonlocal sequence
        sequence += 1
        print('[{}] Got: {}'.format(sequence, result))
    return handler

>>> handler = make_handler()
>>> apply_async(add, (2, 3), callback=handler)
[1] Got: 5
>>> apply_async(add, ('hello', 'world'), callback=handler) 
[2] Got: helloworld
>>>

別の変形は、以下のように、コルーチンを使用することです。

def make_handler(): 
    sequence = 0
    while True:
        result = yield
        sequence += 1
        print('[{}] Got: {}'.format(sequence, result))

>>> handler = make_handler()
>>> next(handler) # Advance to the yield
>>> apply_async(add, (2, 3), callback=handler.send)
[1] Got: 5
>>> apply_async(add, ('hello', 'world'), callback=handler.send) 
[2] Got: helloworld
>>>

最後に、非常に重要なのは、あなたはまた、コールバックに状態を運ぶために追加のパラメータと部分機能を使用することができます。

class SequenceNo:
    def __init__(self):
        self.sequence = 0

def handler(result, seq):
    seq.sequence += 1
    print('[{}] Got: {}'.format(seq.sequence, result))

seq = SequenceNo()
from functools import partial
apply_async(add, (2, 3), callback=partial(handler, seq=seq))
[1] Got: 5
apply_async(add, ('hello', 'world'), callback=partial(handler, seq=seq))
[2] Got: helloworld

ソフトウェアベースのコールバック関数は、多くの場合、リスクの混乱を勇敢に立ち向かいます。問題の一部は、通常、切断コールバックコードへの最初の要求によって引き起こされるコールバック関数に関連付けられています。したがって、要求処理結果との間の実行環境の効果的な損失。あなたは、コールバック・プロセスは、複数の手順が必要と続けたい場合は、状態の関連付けを保存し、復元する方法を見つけ出す必要があります。

キャプチャとキャリーの状態に使用される2つの主な方法は、実際にあります。それは(結合法に取り付けられている)クラスのインスタンスで実行することができる、それはクロージャ(内部関数)で行うことができます。それらは唯一の機能により構成されているので、両方の技術では、クロージャは、より自然な、軽量であってもよいです。彼らはまた、自動的に使用されているすべての変数を取り込みます。(コードによって自動的に決定される)の正確な状態を格納することが、もはや必要。

それは密接に閉鎖法に関連しているため、コールバックハンドラとしてコルーチン使用することは興味深いものです。それは一つだけの機能を持っているので、ある意味では、それは、もっときれいです。また、変数はローカル以外の文を恐れることなく、自由に変更することができます。

潜在的な欠点は、Pythonのコルーチンとして簡単に理解されていない残りのです。そのような()コルーチンにコルーチンを使用する前に、次のコールする必要など、いくつかの困難な問題があります。実際には、忘れがちです。それにもかかわらず、コルーチン他の潜在的用途、例えばインラインコールバック(インラインコールバック)定義。

おすすめ

転載: www.cnblogs.com/jeffrey-yang/p/11986512.html