2012-04-28 3 views
26

Wenn eine Funktion eine Variable im globalen Bereich erklärt ändern muss, müssen sie die globale Deklaration verwenden. Wenn jedoch die Funktion nur eine globale Variable lesen muss, kann es tun, ohne eine globale Erklärung mit:Python: Warum wird global nur bei Zuweisung und nicht bei Lesevorgängen benötigt?

X = 10 
def foo(): 
    global X 
    X = 20 # Needs global declaration 
def bar(): 
    print(X) # Does not need global 

Meine Frage ist, über die Gestaltung von Python: Warum ist Python entwickelt, um die Lese von globalen Variablen zu ermöglichen, ohne Verwenden Sie die globale Deklaration? Das heißt, warum nur global zu erzwingen, warum nicht global forcieren? (Das würde es gleichmäßig und elegant machen.)

Hinweis: Ich kann sehen, dass es keine Mehrdeutigkeit beim Lesen gibt, aber während der Zuweisung ist nicht klar, ob man eine neue lokale Variable erstellen oder der globalen zuweisen möchte. Aber ich hoffe, dass es einen besseren Grund oder eine Absicht zu dieser unausgewogenen Designwahl durch den BDFL gibt.

+2

Um kleine Fehler zu verstecken? – Inverse

Antwort

15

Blick auf diesen Code:

from module import function 

def foo(x): 
    return function(x) 

Der Name function hier ist ein global. Es würde schrecklich langweilig werden, wenn ich sagen müsste, dass dieser Code funktioniert.

Bevor Sie sagen, dass Ihre X und meine function unterschiedlich sind (weil eine eine Variable ist und die andere eine importierte Funktion ist), beachten Sie, dass alle Namen in Python gleich behandelt werden: wenn sie verwendet werden, wird ihr Wert nachgeschlagen die Bereichshierarchie. Wenn Sie global X benötigen, benötigen Sie global function. Ick.

+3

Das beantwortet die Frage allerdings nicht wirklich. Sie könnten dieses Argument auch auf das Modifizieren von Globalen anwenden. Warum das explizite Globale zum Modifizieren von Globalen? – jterrace

+3

Wenn Sie '' globales X' 'nicht einschließen, würde die Anweisung 'X = 10' ein lokales' X' erzeugen, das an '10' gebunden ist, anstatt das globale' X' an '10' zu binden. –

+4

@jterrace: Die Frage war: "Warum wird global * nur * im Einsatz benötigt?“Nicht,‚warum ist global auf Zuweisung benötigt‘ –

24

Mit verschachtelten Bereiche sind die variable Lookups einfach. Sie treten in einer Kette auf, die mit Locals beginnt, indem sie Defs umschließt, zu Modul Globals und dann zu Builtins. Die Regel ist das erste gefundene Match, das gewinnt. Dementsprechend benötigen Sie keine globale Deklaration für Lookups.

Im Gegensatz dazu mit Schreiben müssen Sie angeben, welcher Umfang zu schreiben. Es gibt sonst keine Möglichkeit zu bestimmen, ob "x = 10" in der Funktion "in einen lokalen Namespace schreiben" oder "in einen globalen Namespace schreiben" bedeutet.

Zusammenfassung, mit Schreib haben Sie eine Auswahl von Namensraum, aber mit Lookups die erste gefundene Regel genügt. Hoffe, das hilft :-)

Edit: Ja, es ist so, "weil der BDFL so sagte", aber es ist nicht ungewöhnlich in anderen Sprachen ohne Typ-Deklarationen eine First-Found-Regel für Lookups und nur zu haben erfordern einen Modifikator für nichtlokale Schreibvorgänge. Wenn Sie darüber nachdenken, führen diese beiden Regeln zu sehr sauberem Code, da die Bereichsmodifikatoren nur im seltensten Fall benötigt werden (nichtlokale Schreibvorgänge).

+2

+1 für LEGB, fand ich immer seine einfache – okm

16

Da explizite ist besser als implizit.

Es gibt keine Zweideutigkeit, wenn Sie eine Variable lesen. Sie erhalten immer den ersten gefundenen Suchbereich von lokal bis global.

Wenn Sie zuweisen, gibt es nur zwei Bereiche, von denen der Interpreter unmissverständlich annehmen kann, dass Sie zuweisen: lokal und global. Da die Zuweisung zu local der häufigste Fall ist und die Zuweisung zu global eigentlich nicht empfohlen wird, ist dies der Standardwert. Um es global zuzuweisen, müssen Sie es explizit tun und dem Interpreter mitteilen, dass, wo immer Sie diese Variable in diesem Bereich verwenden, es direkt in den globalen Geltungsbereich gehen sollte und Sie wissen, was Sie tun. In Python 3 können Sie auch dem nächstgelegenen umschließenden Scope 'nonlocal' zuweisen.

Denken Sie daran, dass, wenn Sie einem Namen in Python zuweisen, diese neue Zuweisung nichts mit dem zuvor existierenden Namen zu tun hat, der einem anderen Namen zugewiesen wurde. Stellen Sie sich vor, es gäbe keinen Standardwert für local und Python sucht in allen Bereichen nach einer Variablen mit diesem Namen und weist sie dem Lesen beim Lesen zu. Das Verhalten Ihrer Funktionen kann sich nicht nur aufgrund Ihrer Parameter, sondern auch des umgebenden Gültigkeitsbereichs ändern. Das Leben wäre erbärmlich.

+6

Als Randbemerkung zu erinnern, die nicht der Fall ist passen besonders die Antwort, ich habe beruflich seit 8 Jahren in Python Programmierung und I ** ** nie für etwas global verwendet –

+0

Pedro. Wenn Sie ein einfaches Skript schreiben, deren Funktion benötigt globalen Zustand zu ändern, was tun Sie Was ist, wenn Klassen zu schwer für den einfachen Skript sind –

6

Sie sagen es selbst, dass mit liest gibt es keine Mehrdeutigkeit und mit schreibt es gibt. Daher benötigen Sie einen Mechanismus zum Lösen der Mehrdeutigkeit bei Schreibvorgängen.

Eine Option (möglicherweise tatsächlich von viel älteren Versionen von Python, IIRC verwendet) ist nur zu sagen, dass Schreibvorgänge immer zum lokalen Bereich gehen. Dann brauchen Sie kein Schlüsselwort global und keine Mehrdeutigkeit. Aber dann können Sie überhaupt nicht in globale Variablen schreiben (ohne Dinge wie globals() zu verwenden, um sie in einer Runde zu bekommen), also wäre das nicht großartig. Eine andere Option, die von Sprachen verwendet wird, die Variablen statisch deklarieren, besteht darin, für jeden Bereich mit der Sprachimplementierung zu kommunizieren, deren Namen lokal sind (die Sie in diesem Bereich deklarieren) und welche Namen global sind der Modulumfang). Da Python jedoch keine Variablen deklariert hat, funktioniert diese Lösung nicht.

Eine andere Option wäre, dass x = 3 nur dann einer lokalen Variablen zugewiesen wird, wenn in einem äußeren Bereich bereits ein Name mit dem Namen x vorhanden ist. Scheint es würde intuitiv das Richtige tun? Es würde jedoch zu einigen ernsthaften Eckenfällen führen. Derzeit, wo x = 3 schreiben wird, wird statisch vom Parser bestimmt; Entweder gibt es keine global x im selben Bereich und es ist ein lokaler Schreibvorgang, oder es gibt einen global x und es ist ein globaler Schreibvorgang. Aber wenn das, was es tun wird, vom globalen Modulumfang abhängt, müssen Sie bis zur Laufzeit warten, um zu bestimmen, wohin der Schreibvorgang geht , was bedeutet, dass er zwischen Aufrufen einer Funktion wechseln kann. Denk darüber nach. Jedes Mal, wenn Sie in einem Modul eine globale Variable erstellen, ändern Sie das Verhalten aller Funktionen in dem Modul, das diesen Namen als lokalen Variablennamen verwendet hat. Führen Sie eine Berechnung des Modulumfangs durch, die tmp als temporäre Variable verwendet, und verabschieden Sie sich mit tmp in alle Funktionen im Modul. Und ich schaudere, um an die obskuren Fehler zu denken, die das Zuordnen eines Attributs zu einem Modul, das Sie importiert haben, und das anschließende Aufrufen einer Funktion von diesem Modul betreffen. Yuck.

Und eine weitere Option besteht darin, der Sprachimplementierung bei jeder Zuweisung mitzuteilen, ob sie lokal oder global sein soll. Damit ist Python gegangen. Da es einen vernünftigen Standard gibt, der fast alle Fälle abdeckt (in eine lokale Variable schreiben), haben wir eine lokale Zuweisung als Standard und markieren explizit globale Zuweisungen mit global.


Es gibt eine Mehrdeutigkeit mit Zuweisungen, die einen Mechanismus zur Lösung benötigt. global ist ein solcher Mechanismus. Es ist nicht das einzig mögliche, aber im Kontext von Python scheint es, dass alle alternativen Mechanismen schrecklich sind. Ich weiß nicht, welchen "besseren Grund" du suchst.

+0

Ben:. Python-Neuling hier ist es möglich, „zu injizieren“, um eine neue globale Variable zur Laufzeit abgesehen von th Welche sind bereits im Quellcode auf globaler Ebene aufgeführt? Ihre Antworten scheinen dies zu zeigen, ich würde gerne wissen, wie das möglich ist. –

+1

@Ashwin Der globale Bereich unterscheidet sich nicht von anderen Bereichen. Es gibt keine einzige statische Deklaration dessen, was es enthält; Python führt den Code einfach in einem Modul aus, wodurch Namen im globalen Gültigkeitsbereich zugewiesen werden. Dies ist genau die gleiche Art, wie Namen im lokalen Bereich definiert sind. Hinzu kommt, dass auch jedes andere Code mit einem Verweis auf das Modul (nach dem Import) kann attribtues darauf und Modulattribute sind nur die globalen Variablen in diesem Modul zugeordnet werden. Plus-Funktionen im Modul könnten 'global' verwenden. Ist das die Art von Dingen, auf die du dich beziehst? – Ben

+0

Ben: Verstanden. Vielen Dank :-) –