2016-10-25 1 views
0

我々が原因それのスコープに、この「落とし穴」Pythonで持つ一般精通している:今後のコールバッククロージャで証明スコープ[Pythonの]

functions = [] 
for i in range(3): 
    functions.append(lambda : i) 

out = [f() for f in functions] 

# naive expectation = [0, 1, 2] 
# actual result = [2, 2, 2] 

そして、我々は、一般的に我々の期待と一致する方法に精通している:

functions.append(lambda i=i: i) 

しかし、「将来の証明」コールバッククロージャを作成しようとする中で、コールバックシグネチャが拡張される可能性がクロージャの範囲を定義するために使用されるデフォルトの引数を壊すという問題が発生しました。


この場合考えてみましょう:あなたは、いくつかの新しい機能を収納する新しい引数を追加する必要がある場合

def old_style_callback(data, *args, **kwargs): 
    # ... 

# define a bunch of closures 
closures = [] 
for cb in list_of_callbacks: 
    def old_style_closure(data, callback=cb, *args, **kwargs): 
     cb(data, *args, **kwargs) 
     # ... 
    closures.append(old_style_closure) 

しかし、何を?

def new_style_callback(data, metadata, *args, **kwargs): 
    # ... 

metadataあなたはクロージャのスコープを拡張し、コールバックにアクセスするために使用されるデフォルトの引数に渡されますので、今すぐあなたのold_style_closureは、破損しています!


"将来の証明"コールバッククロージャが必要な場合は、元の署名に固執し、これらの引数をすべて渡すだけです。これはあまりにもひどいことではありませんが、元の署名を十分に一般化していないと問題が発生します。

この問題に対する考え方や新しいアプローチは高く評価されます。

答えて

0

この問題を書くと、この問題を解決するには、という新しい機能を作成して、クロージャを作成することができます。いったんそれを持っていれば、それをループ内に呼び出すだけです:

def create_callback_closure(callback): 
    def old_style_closure(data, *args, **kwargs): 
     callback(data, *args, **kwargs) 
     # ... 

closures = [] 
for cb in list_of_callbacks: 
    closures.append(create_callback_closure(callback)) 
関連する問題