Namens-Lookup in Comprehensions

06/08/2011 - 04:08 von Torsten Bronger | Report spam
Hallöchen!

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? 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.

Was sagt ihr dazu?

Tschö,
Torsten.

Torsten Bronger Jabber-ID: torsten.bronger@jabber.rwth-aachen.de
oder http://bronger-jmp.appspot.com
 

Lesen sie die antworten

#1 Stefan Behnel
06/08/2011 - 06:58 | Warnen spam
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/...sses-scope

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

http://docs.python.org/tutorial/cla...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

Ähnliche fragen