2016-10-25 3 views
0

Wir sind in der Regel mit diesem "Gotcha" in Python vertraut aufgrund seines Scoping:Future Proof Scoping In Rückruf Closures [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] 

Und wir sind im Allgemeinen bekannt, wie unsere Erwartungen entsprechen:

Beim Versuch, "zukunftssichere" Callback-Schließungen zu erstellen, habe ich jedoch ein Problem festgestellt, bei dem die Möglichkeit einer erweiterten Callback-Signatur die Standardargumente zur Definition des Umfangs der Schließung unterbricht.


Betrachten wir diesen Fall:

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) 

Aber was, wenn Sie ein neues Argument hinzufügen müssen, die einige neue Funktionen bietet Platz? Jetzt

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

Ihre old_style_closure wurde gebrochen, da metadata wird das Standardargument übergeben bekommen Sie verwendeten die Schließung des Anwendungsbereich zu erweitern und den Rückruf zugreifen!


Es scheint, als wenn Sie „zukunftssicher“ Callback-Verschlüsse wollen, sind Sie mit Ihrer Originalunterschrift zu bleiben gezwungen und einfach alles durch diese Argumente übergeben. Das ist nicht so schlimm, aber das stellt ein Problem dar, wenn Sie Ihre ursprüngliche Signatur nicht generisch genug gemacht haben.

Alle Gedanken oder neue Ansätze zu diesem Problem sind willkommen.

Antwort

0

Nach dem Schreiben dieser Frage kam ich zu der Erkenntnis, dass Sie dieses Problem lösen können, indem Sie eine neue Funktion mit eigenen Bereich erstellen, um den Abschluss zu erstellen. Sobald Sie das haben, nennen Sie es einfach In-Loop:

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))