[Python-de] Namens-Lookup in Comprehensions

Stefan Behnel python-de at behnel.de
Sa Aug 6 06:58:37 CEST 2011


Torsten Bronger, 06.08.2011 04:08:
> Folgender Code:
>
> class Test(object):
>      s = 2
>      dict([(x, s) for x in range(10)])
>      dict((x, s) for x in range(10))
>
> Warum bricht Python (zumindest CPython) die Ausführung der letzten
> Zeile ab, weil er "s" nicht findet?
>
> CPython3 mag schon die Zeile davor nicht.  Ich weiß, daß Python3
> dahingehend geändert wurde, daß "x" nicht mehr nach draußen sichtbar
> ist, aber darum geht es hier ja nicht.
>
> Und überhaupt: Was ist der Grund, warum in solchen Ausdrücken der
> Klassenvariablen-Namensraum quasi übersprungen wird und der
> Interpreter gleich im umgebenden Namensraum sucht?

Klassen haben in Python keinen Scope. Das hat erstmal auch nichts mit 
Generator-Expressions zu tun. Siehe z.B.

http://stackoverflow.com/questions/1765677/python-nested-classes-scope

Die Python-Doku enthält einen längeren Abschnitt über Scopes und Namespaces.

http://docs.python.org/tutorial/classes.html#python-scopes-and-namespaces


> Man kann das Beispiel noch etwas weitertreiben:
>
> def super():
>      s = 4
>      class Test(object):
>          s = 2
>          print(dict([(x, s) for x in range(10)]))
>          print(dict((x, s) for x in range(10)))
> super()
>
> Führt das mal in python und python3 aus.  Das Ergebnis ist in beiden
> Fällen unterschiedlich (soweit okay) aber auch in beiden Fällen --
> gelinde gesagt -- überraschend.

Na ja, sagen wir mal, es ist inkonsistent in Python 2.x, wo 
List-Comprehensions noch keinen eigenen Scope hatten. Das führt dann zu 
solchen Auswüchsen hier:

   Python 2.7.1+ (2.7:c821d3d335e8, Apr 22 2011, 18:45:36)
   [GCC 4.4.3] on linux2
   Type "help", "copyright", "credits" or "license" for more information.
   >>> def super():
   ...     s = 4
   ...     class Test(object):
   ...         s = 2
   ...         print(dict([(x, s) for x in range(10)]))
   ...         print({x : s for x in range(10)})
   ...         print(dict((x, s) for x in range(10)))
   ...
   >>> super()
   {0: 2, 1: 2, 2: 2, 3: 2, 4: 2, 5: 2, 6: 2, 7: 2, 8: 2, 9: 2}
   {0: 4, 1: 4, 2: 4, 3: 4, 4: 4, 5: 4, 6: 4, 7: 4, 8: 4, 9: 4}
   {0: 4, 1: 4, 2: 4, 3: 4, 4: 4, 5: 4, 6: 4, 7: 4, 8: 4, 9: 4}

Das wurde in Python 3 vereinheitlicht und nun funktionieren die Scopes von 
Generator-Expressions und allen Comprehensions genauso wie die von Funktionen.

Stefan


Mehr Informationen über die Mailingliste python-de