Scoping in Python 'for'-Schleifen


177

Ich frage nicht nach Pythons Scoping-Regeln. Ich verstehe allgemein, wie das Scoping in Python für Schleifen funktioniert. Meine Frage ist, warum die Entwurfsentscheidungen auf diese Weise getroffen wurden. Zum Beispiel (kein Wortspiel beabsichtigt):

for foo in xrange(10):
    bar = 2
print(foo, bar)

Das obige wird gedruckt (9,2).

Das kommt mir komisch vor: 'foo' steuert wirklich nur die Schleife, und 'bar' wurde innerhalb der Schleife definiert. Ich kann verstehen, warum es möglicherweise erforderlich ist, dass 'bar' außerhalb der Schleife zugänglich ist (andernfalls hätten Schleifen nur eine sehr eingeschränkte Funktionalität). Was ich nicht verstehe, ist, warum die Steuervariable nach dem Beenden der Schleife im Gültigkeitsbereich bleiben muss. Nach meiner Erfahrung ist der globale Namespace einfach unübersichtlich und es ist schwieriger, Fehler aufzuspüren, die von Dolmetschern in anderen Sprachen abgefangen würden.


6
Wenn Sie nicht möchten, dass die forSchleife Ihren globalen Namespace überfüllt, schließen Sie sie in eine Funktion ein. Schließungen in Hülle und Fülle!
Nathanismus

24
Sofern Sie keine Schleife im globalen Namespace ausführen (ungewöhnlich), wird ein lokaler Namespace überladen.
Glenn Maynard

2
Wenn dies nicht vorhanden wäre, wie würden Sie die Verarbeitung später an dem Punkt fortsetzen, an dem Sie innerhalb der Schleife aufgehört haben? Definieren Sie einfach die Steuervariable vor der Schleife?
Endolith

8
@endolith Ja ... Warum nicht das verlangen?
Steven Lu

3
Nun, die Leute werden es einfach vorziehen, was sie gewohnt sind. Ich würde sagen, dass solche Dinge dem Python-Codierer weh tun, der sich an solche Dinge gewöhnt und einen schmerzhaften Prozess durchlaufen muss, wenn er in eine andere Sprache wechselt. Für den Rest von uns ist es eine nette kleine Abkürzung, nehme ich an.
Steven Lu

Antworten:


107

Die wahrscheinlichste Antwort ist, dass es nur die Grammatik einfach hält, kein Stolperstein für die Annahme war und viele glücklich waren, den Umfang, zu dem ein Name gehört, nicht eindeutig definieren zu müssen, wenn sie ihm innerhalb eines Schleifenkonstrukts zugewiesen werden. Variablen werden nicht innerhalb eines Bereichs deklariert, sondern durch den Speicherort von Zuweisungsanweisungen impliziert. Das globalSchlüsselwort existiert nur aus diesem Grund (um anzuzeigen, dass die Zuweisung in einem globalen Bereich erfolgt).

Aktualisieren

Hier ist eine gute Diskussion zum Thema: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

Frühere Vorschläge, for-Schleifenvariablen lokal für die Schleife zu machen, sind auf das Problem des vorhandenen Codes gestoßen, der darauf beruht, dass die Schleifenvariable ihren Wert nach dem Verlassen der Schleife beibehält, und es scheint, dass dies als wünschenswertes Merkmal angesehen wird.

Kurz gesagt, Sie können wahrscheinlich die Python-Community dafür verantwortlich machen: P.


2
Wie wäre die Grammatik komplizierter, wenn der Umfang der Induktionsvariablen auf den Körper der Schleife beschränkt wäre? Eine solche Änderung würde sich auf die semantische Analyse in Python beschränken, nicht auf die Grammatik.
Charles

6
Schleifen sind in Python keine Blöcke. Diese Art von Verhaltensänderung würde erfordern, entweder die Grammatik grundlegend zu ändern oder einen Sonderfall bereitzustellen. Das gesamte Konzept einer Induktionsvariablen wird in der aktuellen Grammatik ebenfalls nicht ausgedrückt. Die Grammatik liefert den Vertrag darüber, wie der Dolmetscher interpretieren wird. Mein Punkt ist, dass ich nicht vorhersehen kann, wie eine Änderung dieses Verhaltens vorgenommen werden kann, ohne die Grammatik komplizierter zu machen. Es ist alles umstritten, da der Nebeneffekt der Entwurfsentscheidung zu einem Merkmal geworden ist.
Jeremy Brown

1
Dieser Beitrag hier mail.python.org/pipermail/python-dev/2005-September/056677.html enthält weitere Details zu Geschwindigkeit und Komplikationen, auf die Mr. Brown anspielt.
Rajesh

61

Python hat keine Blöcke, ebenso wie einige andere Sprachen (wie C / C ++ oder Java). Daher ist die Scoping-Einheit in Python eine Funktion.


3
Ich bin verwirrt - was hindert Python daran, Schleifen genauso zu suchen wie Funktionen?
Chimeracoder

35
Nicht wirklich wahr, es ist nur so, dass die Grammatik nicht blockverrückt wird. ( docs.python.org/reference/… ) "Ein Block ist ein Teil des Python-Programmtextes, der als Einheit ausgeführt wird. Die folgenden Blöcke sind: ein Modul, ein Funktionskörper und eine Klassendefinition ..."
Jeremy Brown

1
@ thebackhand, nichts. Es wurde einfach als unnötig erachtet.
Hablabit

@ Jeremy Brown - in der Tat. Gute Notiz.
Atzz

6
@thebackhand - In Sprachen mit Blöcken ist das Scoping von forSchleifen eine natürliche Erweiterung eines allgemeinen Prinzips. In Python müsste es ein Sonderfall sein, und Sonderfälle sollten vermieden werden, es sei denn, sie haben überzeugende Vorteile.
Atzz

39

Ein wirklich nützlicher Fall hierfür ist die Verwendung enumerateund Sie möchten am Ende die Gesamtzahl:

for count, x in enumerate(someiterator, start=1):
    dosomething(count, x)
print "I did something {0} times".format(count)

Ist das notwendig? Nein, aber es ist sicher bequem.

Eine andere Sache, die Sie beachten sollten: In Python 2 werden auch Variablen im Listenverständnis durchgesickert:

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9

Gleiches gilt jedoch nicht für Python 3.


4
Sie hätten das vermutlich in der elseKlausel tun können , dh. else: print "I did something {0} times".format(count)- bevor der lokale Bereich (der in Python nicht vorhanden ist) verschwindet
Nas Banov

3
Nur das zweite Beispiel funktioniert in Python 3 nicht, oder? Das erste noch? Hinweise, warum es aus Python 3 entfernt wurde?
Endolith

7
für die Zählung Element in Aufzählung (a, Start = 1): # Standardindex ist von Null
Tao Zhang

3
Das erste Beispiel scheint kein guter Anwendungsfall zu sein, sondern eher der Beweis dafür, dass diese Geltungsbereichsregel gefährlich ist und nicht als verlässlich angesehen werden sollte. Was ist, wenn someiteratores leer ist?
Max

1
@Nas Während elsein diesem Fall eine Klausel verwendet werden könnte, würde sie im Allgemeinen nicht funktionieren, da der Schleifenkörper breakvorzeitig funktionieren könnte .
Jamesdlin

2

Wenn Sie eine break-Anweisung in der Schleife haben (und den Iterationswert später verwenden möchten, um möglicherweise etwas abzurufen, zu indizieren oder den Status anzugeben), werden Ihnen eine Codezeile und eine Zuweisung erspart, sodass Sie bequem arbeiten können.


1

Einer der wichtigsten Einflüsse für Python ist ABC , eine in den Niederlanden entwickelte Sprache, um Anfängern Programmierkonzepte beizubringen. Der Schöpfer von Python, Guido van Rossum, arbeitete in den 1980er Jahren mehrere Jahre an ABC. Ich weiß fast nichts über ABC, aber da es für Anfänger gedacht ist, muss es vermutlich eine begrenzte Anzahl von Bereichen haben, ähnlich wie bei frühen BASICs.


-1

Wenn Variablen für Schleifen lokal wären, wären diese Schleifen für die meisten realen Programme nutzlos.

In der aktuellen Situation:

# Sum the values 0..9
total = 0
for foo in xrange(10):
    total = total + foo
print total

ergibt 45. Überlegen Sie nun, wie die Zuweisung in Python funktioniert. Wenn Schleifenvariablen streng lokal wären:

# Sum the values 0..9?
total = 0
for foo in xrange(10):
    # Create a new integer object with value "total + foo" and bind it to a new
    # loop-local variable named "total".
    total = total + foo
print total

ergibt 0, weil totalinnerhalb der Schleife nach der Zuweisung nicht die gleiche Variable wie totalaußerhalb der Schleife ist. Dies wäre kein optimales oder erwartetes Verhalten.


5
Die Frage nicht beantworten. Das OP fragte nach foo, nicht total (oder bar in ihrem Beispiel).
James Bradbury

6
@JamesBradbury totalund foohätte immer noch schleifenlokale Bindungen im OP-Szenario und die Logik ist dieselbe.
Kirk Strauser

2
OP: "Ich kann verstehen, warum es erforderlich sein kann, dass 'bar' außerhalb der Schleife zugänglich ist (andernfalls hätten Schleifen nur eine sehr eingeschränkte Funktionalität). Ich verstehe nicht, warum die Steuervariable erhalten bleiben muss im Gültigkeitsbereich nach dem Beenden der Schleife. " (Hervorhebung von mir)
James Bradbury

2
@ JamesBradbury Sie haben vielleicht Recht, aber ich habe dies vor drei Jahren beantwortet und es lohnt sich wahrscheinlich nicht, jetzt darüber zu diskutieren.
Kirk Strauser
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.