533 Stimmen

Kurze Beschreibung der Geltungsbereichsregeln

Was sind genau die Python-Bereichsbereiche?

Wenn ich etwas Code habe:

code1
class Foo:
   code2
   def spam.....
      code3
      for code4..:
       code5
       x()

Wo wird x gefunden? Einige mögliche Optionen sind unten aufgeführt:

  1. Im umgebenden Quellcode
  2. Im Klassenbereich
  3. In der Funktionsdefinition
  4. In der Schleifenindexvariable
  5. Innerhalb der Schleife

Auch gibt es den Kontext während der Ausführung, wenn die Funktion spam an anderer Stelle übergeben wird. Und vielleicht werden Lambda-Funktionen etwas anders übergeben?

Es muss irgendwo eine einfache Referenz oder Algorithmus geben. Es ist eine verwirrende Welt für fortgeschrittene Python-Programmierer.

4 Stimmen

Die Geltungsbereichsregeln werden ziemlich knapp, aber auch vollständig, in der Python-Dokumentation beschrieben: docs.python.org/3/reference/….

16voto

S.Lott Punkte 371691

Python löst Ihre Variablen mit -- im Allgemeinen -- drei verfügbaren Namensräumen.

Zu jedem Zeitpunkt während der Ausführung gibt es mindestens drei verschachtelte Scopes, deren Namensräume direkt zugänglich sind: der innerste Scope, der zuerst durchsucht wird, enthält die lokalen Namen; die Namensräume eventuell umgebender Funktionen, die beginnend mit dem nächstgelegenen umgebenden Scope durchsucht werden; der mittlere Scope, der als nächstes durchsucht wird, enthält die globalen Namen des aktuellen Moduls; und der äußerste Scope (der zuletzt durchsucht wird) ist der Namensraum, der die eingebauten Namen enthält.

Es gibt zwei Funktionen: globals und locals, die Ihnen die Inhalte zwei dieser Namensräume zeigen.

Namensräume werden von Paketen, Modulen, Klassen, Objektkonstruktionen und Funktionen erstellt. Es gibt keine anderen Varianten von Namensräumen.

In diesem Fall muss der Aufruf einer Funktion mit dem Namen x im lokalen Namensraum oder im globalen Namensraum aufgelöst werden.

Lokal ist in diesem Fall der Körper der Methodenfunktion Foo.spam.

Global ist -- nun ja -- global.

Die Regel besagt, dass die verschachtelten lokalen Räume, die durch Methodenfunktionen (und verschachtelte Funktionsdefinitionen) erstellt wurden, durchsucht werden sollen, dann wird global durchsucht. Das war's.

Es gibt keine anderen Scopes. Die for-Anweisung (und andere Zusammengesetzte Anweisungen wie if und try) erstellen keine neuen verschachtelten Scopes. Nur Definitionen (Pakete, Module, Funktionen, Klassen und Objektinstanzen.)

In einer Klassendefinition sind die Namen Teil des Klassen-Namensraums. code2 muss beispielsweise durch den Klassennamen qualifiziert werden. Allgemein Foo.code2. Jedoch funktioniert auch self.code2, weil Python-Objekte die enthaltende Klasse als Fallback betrachten.

Ein Objekt (eine Instanz einer Klasse) hat Instanzvariablen. Diese Namen befinden sich im Namensraum des Objekts. Sie müssen durch das Objekt qualifiziert werden. (variable.instanz.)

Von innerhalb einer Klassenmethode aus haben Sie Lokale und Globale. Sie sagen self.variable, um die Instanz als Namensraum auszuwählen. Sie werden feststellen, dass self ein Argument für jede Klassenmitgliedsfunktion ist und somit Teil des lokalen Namensraums ist.

Siehe Python Scope-Regeln, Python Scope, Variable Scope.

6 Stimmen

Dies ist veraltet. Seit 2.1 (vor 7 Jahren) gibt es mehr als zwei Bereiche, da verschachtelte Funktionen neue Bereiche einführen, sodass eine Funktion innerhalb einer Funktion Zugriff auf ihren lokalen Bereich, den umgebenden Funktionenbereich und den globalen Bereich (auch eingebaute) hat.

0 Stimmen

Es tut mir leid, das ist nicht mehr der Fall. Python hat zwei verfügbare Namensräume. Global und lokal zu etwas.

10voto

bobince Punkte 512550

Wo wird x gefunden?

x wird nicht gefunden, da du es nicht definiert hast. :-) Es könnte in code1 (global) oder code3 (lokal) gefunden werden, wenn du es dort platzierst.

code2 (Klassenmember) sind für den Code innerhalb der Methoden derselben Klasse nicht sichtbar - du würdest normalerweise über self darauf zugreifen. code4/code5 (Schleifen) existieren im gleichen Gültigkeitsbereich wie code3, also wenn du in ihnen etwas nach x schreibst, würdest du die x-Instanz ändern, die in code3 definiert wurde, anstatt ein neues x zu erstellen.

In Python wird statisch geschlossen, also wenn du 'spam' an eine andere Funktion übergibst, hat spam immer noch Zugriff auf globale Variablen im Modul, aus dem es stammt (definiert in code1), und alle anderen umschließenden Gültigkeitsbereiche (siehe unten). Mitglieder von code2 würden wieder über self zugegriffen.

Lambda unterscheidet sich nicht von def. Wenn du ein Lambda innerhalb einer Funktion verwendest, ist es dasselbe wie das Definieren einer verschachtelten Funktion. Ab Python 2.2 sind verschachtelte Gültigkeitsbereiche verfügbar. In diesem Fall kannst du x auf jeder Ebene der Funktionsverschachtelung binden und Python wird die innerste Instanz wählen:

x= 0
def fun1():
    x= 1
    def fun2():
        x= 2
        def fun3():
            return x
        return fun3()
    return fun2()
print fun1(), x

2 0

fun3 sieht die Instanz x aus dem nächstgelegenen umschließenden Gültigkeitsbereich, der mit fun2 verbunden ist. Aber die anderen x-Instanzen, die in fun1 und global definiert sind, sind nicht betroffen.

Vor nested_scopes - in Python vor Version 2.1 und in Version 2.1, es sei denn, du bittest explizit um das Feature mit einem from-future-import - sind die Gültigkeitsbereiche von fun1 und fun2 für fun3 nicht sichtbar, sodass die Antwort von S.Lott gilt und du die globale x erhälst:

0 0

7voto

MisterMiyagi Punkte 35992

Le site Python-Namensauflösung kennt nur die folgenden Arten von Geltungsbereichen:

  1. eingebauten Bereich, der die Eingebaute Funktionen , wie zum Beispiel print , int , oder zip ,
  2. Modul globalen Bereich, der immer die oberste Ebene des aktuellen Moduls ist,
  3. drei benutzerdefinierte Bereiche, die ineinander verschachtelt werden können, nämlich
    1. Funktion Abschlussbereich, von jedem umschließenden def Block, lambda Ausdruck oder Verstehen.
    2. Funktion lokalen Bereich, innerhalb einer def Block, lambda Ausdruck oder Verstehen,
    3. Klasse Bereich, innerhalb eines class Block.

Vor allem andere Konstrukte wie if , for , oder with Anweisungen haben keinen eigenen Geltungsbereich.

Das Scoping TLDR : Die Nachschlagen eines Namens beginnt mit dem Bereich, in dem der Name verwendet wird, dann alle umgebenden Bereiche (mit Ausnahme der Klassenbereiche), die Modulglobals und schließlich die Builtins - die erste Übereinstimmung in dieser Suchreihenfolge wird verwendet. Die Auftrag auf einen Bereich bezieht sich standardmäßig auf den aktuellen Bereich - die Sonderformen nonlocal y global muss verwendet werden, um zuweisen. zu einem Namen aus einem äußeren Bereich.

Schließlich können auch Comprehensions und Generatorausdrücke sowie := Zuordnungsausdrücke haben eine besondere Regel, wenn sie kombiniert werden.


Verschachtelte Geltungsbereiche und Namensauflösung

Diese verschiedenen Geltungsbereiche bilden eine Hierarchie, wobei Builtins und Global immer die Basis bilden und Closures, Locals und Class Scope als lexikalisch definiert. Das heißt, dass nur die Verschachtelung im Quellcode von Bedeutung ist, nicht aber z. B. der Aufrufstapel.

print("builtins are available without definition")

some_global = "1"  # global variables are at module scope

def outer_function():
    some_closure = "3.1"  # locals and closure are defined the same, at function scope
    some_local = "3.2"    # a variable becomes a closure if a nested scope uses it

    class InnerClass:
         some_classvar = "3.3"   # class variables exist *only* at class scope

         def nested_function(self):
             some_local = "3.2"   # locals can replace outer names
             print(some_closure)  # closures are always readable
    return InnerClass

Auch wenn class erzeugt einen Bereich und kann verschachtelte Klassen, Funktionen und Comprehensions haben, wobei die Namen der class Bereich sind für eingeschlossene Bereiche nicht sichtbar. Dadurch entsteht die folgende Hierarchie:

 builtins           [print, ...]
 globals            [some_global]
   outer_function     [some_local, some_closure]
     InnerClass         [some_classvar]
     inner_function     [some_local]

Die Namensauflösung beginnt immer mit dem derzeitiger Anwendungsbereich in dem ein Name aufgerufen wird, und geht dann in der Hierarchie nach oben, bis eine Übereinstimmung gefunden wird. Zum Beispiel, wenn Sie some_local innerhalb outer_function y inner_function startet bei der jeweiligen Funktion - und findet sofort die some_local definiert in outer_function y inner_function . Wenn ein Name nicht lokal ist, wird er aus dem nächstgelegenen umschließenden Bereich geholt, der ihn definiert - nachschlagen some_closure y print innerhalb inner_function sucht bis outer_function bzw. Einbauten.


Bereichsdeklarationen und Namensbindungen

Standardmäßig gehört ein Name zu jedem Bereich, in dem er an einen Wert gebunden ist. Die erneute Bindung desselben Namens in einem inneren Bereich erzeugt eine neue Variable mit demselben Namen - zum Beispiel, some_local existiert getrennt in beiden outer_function y inner_function . In Bezug auf den Geltungsbereich umfasst die Bindung jede Anweisung, die den Wert eines Namens festlegt - Zuweisungsanweisungen, aber auch die Iterationsvariable einer for Schleife oder den Namen einer with Kontext-Manager. Bemerkenswert, del gilt auch als Namensbindung.

Wenn sich ein Name auf eine äußere Variable beziehen muss und in einem inneren Bereich gebunden werden, muss der Name als nicht lokal deklariert werden. Für die verschiedenen Arten von umschließenden Bereichen gibt es gesonderte Deklarationen: nonlocal bezieht sich immer auf den nächstgelegenen Abschluss, und global bezieht sich immer auf einen globalen Namen. Bemerkenswert, nonlocal bezieht sich nie auf einen globalen Namen und global ignoriert alle Verschlüsse mit demselben Namen. Es gibt keine Erklärung, die auf den eingebauten Bereich verweist.

some_global = "1"

def outer_function():
    some_closure = "3.2"
    some_global = "this is ignored by a nested global declaration"

    def inner_function():
        global some_global     # declare variable from global scope
        nonlocal some_closure  # declare variable from enclosing scope
        message = " bound by an inner scope"
        some_global = some_global + message
        some_closure = some_closure + message
    return inner_function

Erwähnenswert ist, dass die Funktion local und nonlocal werden zur Kompilierzeit aufgelöst. A nonlocal Name muss in einem äußeren Bereich existieren. Im Gegensatz dazu ist eine global Name kann dynamisch definiert werden und kann jederzeit zum globalen Geltungsbereich hinzugefügt oder aus diesem entfernt werden.


Umfassungen und Zuweisungsausdrücke

Die Scoping-Regeln für List-, Set- und Dict-Comprehensions und Generatorausdrücke sind fast dasselbe wie für Funktionen. Ebenso lauten die Scoping-Regeln für Zuweisungsausdrücke fast wie bei der normalen Namensbindung.

Der Geltungsbereich von Comprehensions und Generatorausdrücken ist derselbe wie der von Funktionen. Alle im Geltungsbereich gebundenen Namen, d. h. die Iterationsvariablen, sind lokale oder geschlossene Ausdrücke in den Geltungsbereichen von Comprehensions/Generatoren und verschachtelten Ausdrücken. Alle Namen, einschließlich der Iterationsvariablen, werden mit der Namensauflösung aufgelöst, die auch innerhalb von Funktionen gilt.

some_global = "global"

def outer_function():
    some_closure = "closure"
    return [            # new function-like scope started by comprehension
        comp_local      # names resolved using regular name resolution
        for comp_local  # iteration targets are local
        in "iterable"
        if comp_local in some_global and comp_local in some_global
    ]

Eine := Zuweisungsausdruck wirkt auf die nächste Funktion, Klasse oder den nächsten globalen Bereich. Insbesondere, wenn das Ziel eines Zuweisungsausdrucks deklariert wurde nonlocal o global im nächstgelegenen Bereich, der Zuweisungsausdruck honoriert dies wie eine reguläre Zuweisung.

print(some_global := "global")

def outer_function():
    print(some_closure := "closure")

Ein Zuweisungsausdruck innerhalb einer Comprehension/eines Generators arbeitet jedoch mit der nächstgelegenen umschließender Geltungsbereich des Verstehens/Generierens, nicht des Geltungsbereichs des Verstehens/Generierens selbst. Wenn mehrere Comprehensions/Generatoren verschachtelt sind, wird der nächstgelegene Funktions- oder globale Bereich verwendet. Da der Bereich der Comprehension/des Generators Closures und globale Variablen lesen kann, ist die Zuweisungsvariable auch in der Comprehension lesbar. Eine Zuweisung aus einer Comprehension in einen Klassenbereich ist nicht zulässig.

print(some_global := "global")

def outer_function():
    print(some_closure := "closure")
    steps = [
        # v write to variable in cotaining scope
        (some_closure := some_closure + comp_local)
        #                 ^ read from variable in containing scope
        for comp_local in some_global
    ]
    return some_closure, steps

Während die Iterationsvariable lokal in der Comprehension ist, in der sie gebunden ist, erstellt das Ziel des Zuweisungsausdrucks keine lokale Variable und wird aus dem äußeren Bereich gelesen:

 builtins           [print, ...]
 globals            [some_global]
   outer_function     [some_closure]
     <listcomp>         [comp_local]

0 Stimmen

Ich denke, deine Antwort ist unvollständig. Die except..as-Anweisung wird auch einen neuen Bereich erstellen. Zum Beispiel, wenn du try: raise ValueError('x'); except ValueError as v: pass eingibst, kannst du nicht auf v außerhalb des Bereichs der except-Klausel zugreifen.

1 Stimmen

@JohnHenckel Das ist kein neuer Gültigkeitsbereich. except löscht sein Ziel aus seinem Gültigkeitsbereich, wenn es fertig ist. Das Ziel folgt den üblichen Gültigkeitsregeln, z.B. es kann sogar als global deklariert und wird in diesem Fall aus dem globalen Gültigkeitsbereich gelöscht. Demonstrator-Code.

0 Stimmen

OMG das ist seltsam. Vielen Dank, dass du mir das erklärt hast.

2voto

GraceMeng Punkte 789

In Python,

jede Variable, der ein Wert zugewiesen ist, ist lokal für den Block, in dem die Zuweisung erscheint.

Wenn eine Variable im aktuellen Bereich nicht gefunden werden kann, verweisen Sie bitte auf die Reihenfolge LEGB.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X