2014-10-22 12 views
8

Liste Comprehensions haben ihren Code direkt in der Funktion platziert, wo sie verwendet werden, wie folgt aus:Warum verwenden Generator-Ausdrücke und Dict/Set-Comprehensions in Python 2 im Gegensatz zu Listen-Comprehensions eine verschachtelte Funktion?

>>> dis.dis((lambda: [a for b in c])) 
    1   0 BUILD_LIST    0 
       3 LOAD_GLOBAL    0 (c) 
       6 GET_ITER    
     >> 7 FOR_ITER    12 (to 22) 
      10 STORE_FAST    0 (b) 
      13 LOAD_GLOBAL    1 (a) 
      16 LIST_APPEND    2 
      19 JUMP_ABSOLUTE   7 
     >> 22 RETURN_VALUE   

Während Generator Ausdrücke und dict/set Comprehensions sind meist in einer separaten verschachtelte Funktion gesetzt, wie folgt aus:

>>> dis.dis((lambda: {a for b in c})) 
    1   0 LOAD_CONST    1 (<code object <setcomp> at 0x7ff41a3d59b0, file "<stdin>", line 1>) 
       3 MAKE_FUNCTION   0 
       6 LOAD_GLOBAL    0 (c) 
       9 GET_ITER    
      10 CALL_FUNCTION   1 
      13 RETURN_VALUE   

>>> dis.dis((lambda: {a for b in c}).func_code.co_consts[1]) 
    1   0 BUILD_SET    0 
       3 LOAD_FAST    0 (.0) 
     >> 6 FOR_ITER    12 (to 21) 
       9 STORE_FAST    1 (b) 
      12 LOAD_GLOBAL    0 (a) 
      15 SET_ADD     2 
      18 JUMP_ABSOLUTE   6 
     >> 21 RETURN_VALUE   

In Python 3 sind alle diese in einer geschachtelten Funktion platziert.

Warum wird der Code in einer separaten verschachtelten Funktion platziert? Ich erinnere mich vage daran, etwas über Leute gelesen zu haben, die Verständnis und/oder Genexpr-Variablen fixieren wollten, die vor langer Zeit in den umgebenden Bereich verschüttet wurden, war das die Lösung für das oder so?

Warum werden List Comprehensions anders als der Rest in Python 2 implementiert? Wegen der Rückwärtskompatibilität? (I dachte Ich hörte die Rede über Verschütten viel reparieren, nachdem Generator Ausdrücke eingeführt wurden, obwohl, aber ich habe gerade wirklich alte Diskussionen gelesen, oder etwas)

Antwort

10

Ja, Sie sind richtig. In Python 3.x wird dies eingeführt, um den Variablenverlust zu beheben. Zitiert aus dem Amt der History of Python blog, geschrieben angeblich von dem BDFL selbst

Wir haben auch eine weitere Änderung in Python 3, zur Verbesserung der Gleichwertigkeit zwischen Listenkomprehensionen und Generator Ausdrücke. In Python 2 die Liste Verständnis „Lecks“ die Schleifensteuervariable in den umgebenden Rahmen:

x = 'before' 
a = [x for x in 1, 2, 3] 
print x # this prints '3', not 'before' 

Dies war ein Artefakt der ursprünglichen Implementierung der Liste Comprehensions; es war jahrelang eines von Pythons "schmutzigen kleinen Geheimnissen". Es begann als ein vorsätzlicher Kompromiss, Listen-Comprehensions blendend schnell zu machen, und während es kein gewöhnlicher Fallstrick für Anfänger war, stach es Leute gelegentlich gelegentlich. Für Generatorausdrücke konnten wir dies nicht tun. Generatorausdrücke werden unter Verwendung von Generatoren implementiert, deren Ausführung einen separaten Ausführungsrahmen erfordert. Daher waren Generatorausdrücke (besonders wenn sie über eine kurze Sequenz iterieren) weniger effizient als Listenerfassungen.

Wie auch immer, in Python 3, haben wir beschlossen, das "schmutzige kleine Geheimnis" von Listenkompromittierungen zu beheben, indem wir dieselbe Implementierungsstrategie wie für Generatorausdrücke verwenden. So wird in Python 3 das obige Beispiel (nach der Änderung print(x) :-) 'vorher' drucken, was beweist, dass das 'x' im Listenverständnis temporär Schatten wirft, aber das 'x' im umgebenden Bereich nicht überschreibt.

Alle Ihre Fragen werden durch den markierten Text beantwortet.

+2

Hier ist [a link] (https://mail.python.org/pipermail/python--3000/2007-March/006017.html) zu dem Thread, wo Nick Coghlan und Georg Brandl die Gründe für die Umsetzung auf diese Weise diskutieren – Felipe

Verwandte Themen