4. Ausführungsmodell

4.1. Aufbau eines Programms

Ein Python-Programm setzt sich aus Codeblöcken zusammen. Ein Block ist ein Teil des Python-Programmtextes, der als Einheit ausgeführt wird. Zu den Blöcken gehören: ein Modul, ein Funktionskörper und eine Klassendefinition. Jeder interaktiv eingegebene Befehl ist ein Block. Eine Skriptdatei (eine Datei, die dem Interpreter als Standardeingabe übergeben oder als Befehlszeilenargument für den Interpreter angegeben wird) ist ein Codeblock. Ein Skriptbefehl (ein Befehl, der in der Befehlszeile des Interpreters mit der Option -c angegeben wird) ist ein Codeblock. Ein Modul, das als Skript der obersten Ebene (als Modul __main__ ) über die Befehlszeile mit dem Argument -m ausgeführt wird, ist ebenfalls ein Codeblock. Das an die integrierten Funktionen eval() und exec() übergebene Zeichenfolgenargument ist ein Codeblock.

Ein Codeblock wird in einem Ausführungsrahmen ausgeführt. Ein Rahmen enthält einige Verwaltungsinformationen (die zur Fehlersuche dienen) und legt fest, wo und wie die Ausführung fortgesetzt wird, nachdem die Ausführung des Codeblocks abgeschlossen ist.

4.2. Benennung und Zuordnung

4.2.1. Namensbindung

Namen beziehen sich auf Objekte. Namen werden durch Namensbindungsoperationen eingeführt.

Die folgenden Konstrukte binden Namen:

  • Formale Parameter von Funktionen,

  • Klassendefinitionen,

  • Funktionsdefinitionen,

  • Zuweisungsausdrücke,

  • Ziele, die als Bezeichner gelten, wenn sie in einer Zuweisung vorkommen:

    • for Schleifenkopf,

    • nach as in einer with -Anweisung, einer except -Klausel, einer except* -Klausel oder im „as“-Muster beim strukturellen Musterabgleich,

    • in einem Erfassungsmuster beim strukturellen Musterabgleich

  • import Aussagen.

  • type Aussagen.

  • Typ-Parameterlisten.

Die Anweisung import in der Form from ... import * bindet alle im importierten Modul definierten Namen, mit Ausnahme derjenigen, die mit einem Unterstrich beginnen. Diese Form darf nur auf Modulebene verwendet werden.

Ein Ziel, das in einer Anweisung vom Typ del vorkommt, gilt für diesen Zweck ebenfalls als gebunden (auch wenn die eigentliche Semantik darin besteht, die Bindung des Namens aufzuheben).

Jede Zuweisungs- oder Importanweisung erfolgt innerhalb eines Blocks, der durch eine Klassen- oder Funktionsdefinition definiert ist, oder auf Modulebene (dem Code-Block der obersten Ebene).

If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal or global. If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.) If a variable is used in a code block but not defined there, it is a free variable.

Jedes Vorkommen eines Namens im Programmtext bezieht sich auf die Bindung dieses Namens, die durch die folgenden Namensauflösungsregeln festgelegt wird.

4.2.2. Namensauflösung

Ein Gültigkeitsbereich legt fest, in welchem Umfang ein Name innerhalb eines Blocks sichtbar ist. Wird eine lokale Variable in einem Block definiert, erstreckt sich ihr Gültigkeitsbereich auf diesen Block. Erfolgt die Definition in einem Funktionsblock, erstreckt sich der Gültigkeitsbereich auf alle Blöcke, die in dem definierenden Block enthalten sind, es sei denn, ein darin enthaltener Block führt eine andere Bindung für den Namen ein.

Wenn ein Name in einem Codeblock verwendet wird, wird er anhand des nächstgelegenen übergeordneten Gültigkeitsbereichs aufgelöst. Die Menge aller solcher Gültigkeitsbereiche, die für einen Codeblock sichtbar sind, wird als Umgebung des Blocks bezeichnet.

Wenn ein Name überhaupt nicht gefunden wird, wird eine Ausnahme vom Typ NameError ausgelöst. Handelt es sich beim aktuellen Gültigkeitsbereich um einen Funktionsbereich und bezieht sich der Name auf eine lokale Variable, die an der Stelle, an der der Name verwendet wird, noch nicht mit einem Wert belegt wurde, wird eine Ausnahme vom Typ UnboundLocalError ausgelöst. UnboundLocalError ist eine Unterklasse von NameError .

Wenn irgendwo innerhalb eines Codeblocks eine Namensbindung stattfindet, werden alle Verwendungen des Namens innerhalb des Blocks als Verweise auf den aktuellen Block behandelt. Dies kann zu Fehlern führen, wenn ein Name innerhalb eines Blocks verwendet wird, bevor er gebunden wurde. Diese Regel ist nicht ganz einfach zu verstehen. Python kennt keine Deklarationen und erlaubt es, dass Namensbindungsoperationen an beliebiger Stelle innerhalb eines Codeblocks stattfinden. Die lokalen Variablen eines Codeblocks lassen sich ermitteln, indem der gesamte Text des Blocks auf Namensbindungsoperationen durchsucht wird. Beispiele finden Sie im FAQ-Eintrag zu UnboundLocalError.

Wenn die Anweisung global innerhalb eines Blocks auftritt, beziehen sich alle Verwendungen der in der Anweisung angegebenen Namen auf die Zuordnungen dieser Namen im obersten Namensraum. Namen werden im obersten Namensraum aufgelöst, indem der globale Namensraum, d. h. der Namensraum des Moduls, das den Codeblock enthält, sowie der „builtins“-Namensraum, der Namensraum des Moduls builtins, durchsucht werden. Der globale Namensraum wird zuerst durchsucht. Werden die Namen dort nicht gefunden, wird als Nächstes der „builtins“-Namensraum durchsucht. Werden die Namen auch im „builtins“-Namensraum nicht gefunden, werden neue Variablen im globalen Namensraum angelegt. Die Anweisung „global“ muss allen Verwendungen der aufgeführten Namen vorangestellt werden.

Die Anweisung global hat denselben Geltungsbereich wie eine Namensbindung im selben Block. Wenn der nächstübergeordnete Geltungsbereich einer freien Variablen eine globale Anweisung enthält, wird die freie Variable als globale Variable behandelt.

Die Anweisung nonlocal bewirkt, dass die entsprechenden Namen auf zuvor gebundene Variablen im nächstübergeordneten Funktionsgültigkeitsbereich verweisen. Wenn der angegebene Name in keinem übergeordneten Funktionsgültigkeitsbereich existiert, wird zur Kompilierungszeit ein SyntaxError ausgelöst. Typ-Parameter können mit der Anweisung nonlocal nicht neu gebunden werden.

Der Namensraum für ein Modul wird automatisch angelegt, sobald das Modul zum ersten Mal importiert wird. Das Hauptmodul eines Skripts heißt immer __main__ .

Klassendefinitionsblöcke und Argumente für exec() und eval() stellen im Zusammenhang mit der Namensauflösung einen Sonderfall dar. Eine Klassendefinition ist eine ausführbare Anweisung, die Namen verwenden und definieren kann. Diese Verweise folgen den üblichen Regeln für die Namensauflösung, mit der Ausnahme, dass ungebundene lokale Variablen im globalen Namensraum gesucht werden. Der Namensraum der Klassendefinition wird zum Attributwörterbuch der Klasse. Der Geltungsbereich von Namen, die in einem Klassenblock definiert werden, ist auf den Klassenblock beschränkt; er erstreckt sich nicht auf die Codeblöcke von Methoden. Dies umfasst Comprehensions und Generatorausdrücke, jedoch nicht Annotations-Geltungsbereiche, die Zugriff auf die Geltungsbereiche ihrer umschließenden Klassen haben. Das bedeutet, dass Folgendes fehlschlagen wird:

Klasse A:
    a = 42
    b = list(a + i for i in range(10))

Folgendes wird jedoch funktionieren:

Klasse A:
    Typ Alias = Nested
    Klasse Nested: pass

print(A.Alias.__value__)  # <type 'A.Nested'>

4.2.3. Gültigkeitsbereiche von Annotationen

Type parameter lists and type statements introduce annotation scopes, which behave mostly like function scopes, but with some exceptions discussed below. Annotations currently do not use annotation scopes, but they are expected to use annotation scopes in Python 3.13 when PEP 649 is implemented.

Annotationsbereiche werden in den folgenden Kontexten verwendet:

  • Typ-Parameterlisten für generische Typ-Aliase.

  • Typ-Parameterlisten für generische Funktionen. Die Annotationen einer generischen Funktion werden innerhalb des Annotationsbereichs ausgeführt, ihre Standardwerte und Dekoratoren hingegen nicht.

  • Typ-Parameterlisten für generische Klassen. Die Basisklassen und Schlüsselwortargumente einer generischen Klasse werden innerhalb des Annotationsbereichs ausgeführt, ihre Dekoratoren jedoch nicht.

  • The bounds and constraints for type variables (lazily evaluated).

  • Der Wert von Typaliasen (:ref:` <lazy-evaluation>`, die verzögert ausgewertet werden).

Annotations-Gültigkeitsbereiche unterscheiden sich in folgenden Punkten von Funktions-Gültigkeitsbereichen:

  • Annotationsbereiche haben Zugriff auf den Namensraum ihrer übergeordneten Klasse. Befindet sich ein Annotationsbereich unmittelbar innerhalb eines Klassenbereichs oder innerhalb eines anderen Annotationsbereichs, der sich wiederum unmittelbar innerhalb eines Klassenbereichs befindet, kann der Code im Annotationsbereich auf im Klassenbereich definierte Namen zugreifen, als würde er direkt innerhalb des Klassenkörpers ausgeführt. Dies steht im Gegensatz zu regulären, innerhalb von Klassen definierten Funktionen, die keinen Zugriff auf im Klassenbereich definierte Namen haben.

  • Ausdrücke in Annotationsbereichen dürfen keine Ausdrücke vom Typ yield, yield from, await oder := enthalten. (Diese Ausdrücke sind in anderen Bereichen zulässig, die innerhalb des Annotationsbereichs enthalten sind.)

  • Namen, die in Annotationsbereichen definiert wurden, können nicht mit nonlocal-Anweisungen in inneren Bereichen neu definiert werden. Dies betrifft ausschließlich Typparameter, da keine anderen syntaktischen Elemente, die innerhalb von Annotationsbereichen vorkommen können, neue Namen einführen können.

  • Annotationsbereiche verfügen zwar über einen internen Namen, dieser Name spiegelt sich jedoch nicht im qualifizierten Namen der innerhalb des Bereichs definierten Objekte wider. Stattdessen entspricht der __qualname__ solcher Objekte dem, als wäre das Objekt im übergeordneten Bereich definiert.

Added in version 3.12: Annotationsbereiche wurden in Python 3.12 als Teil von PEP 695 eingeführt.

4.2.4. Verzögerte Auswertung

The values of type aliases created through the type statement are lazily evaluated. The same applies to the bounds and constraints of type variables created through the type parameter syntax. This means that they are not evaluated when the type alias or type variable is created. Instead, they are only evaluated when doing so is necessary to resolve an attribute access.

Beispiel:

>>> type Alias = 1/0
>>> Alias.__value__
Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero
>>> def func[T: 1/0](): pass
>>> T = func.__type_params__[0]
>>> T.__bound__
Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero

Hier wird die Ausnahme nur ausgelöst, wenn auf das Attribut __value__ des Typalias oder auf das Attribut __bound__ der Typvariablen zugegriffen wird.

Dieses Verhalten ist vor allem bei Verweisen auf Typen nützlich, die zum Zeitpunkt der Erstellung des Typalias oder der Typvariablen noch nicht definiert waren. So ermöglicht die verzögerte Auswertung beispielsweise die Erstellung von gegenseitig rekursiven Typalias:

from typing import Literal

type SimpleExpr = int | Parenthesized
type Parenthesized = tuple[Literal["("], Expr, Literal[")"]]
type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr]

Verzögerte ausgewertete Werte werden im Annotationsbereich ausgewertet, was bedeutet, dass Namen, die innerhalb des verzögertausgewerteten Werts vorkommen, so nachgeschlagen werden, als würden sie im unmittelbar umgebenden Bereich verwendet.

Added in version 3.12.

4.2.5. Eingebaute Funktionen und eingeschränkte Ausführung

Benutzer sollten __builtins__ nicht ändern; es handelt sich dabei ausschließlich um ein Implementierungsdetail. Benutzer, die Werte im Namespace „builtins“ überschreiben möchten, sollten das Modul builtins über import laden und dessen Attribute entsprechend anpassen.

Der mit der Ausführung eines Codeblocks verbundene „builtins“-Namensraum wird tatsächlich durch Abfrage des Namens __builtins__ in dessen globalem Namensraum ermittelt; dabei sollte es sich um ein Wörterbuch oder ein Modul handeln (im letzteren Fall wird das Wörterbuch des Moduls verwendet). Standardmäßig ist __builtins__ im Modul __main__ das eingebaute Modul builtins ; in jedem anderen Modul ist __builtins__ ein Alias für das Wörterbuch des Moduls builtins selbst.

4.2.6. Interaktion mit dynamischen Funktionen

Die Auflösung freier Variablen erfolgt zur Laufzeit und nicht zur Kompilierungszeit. Das bedeutet, dass der folgende Code 42 ausgibt:

i = 10
def f():
    print(i)
i = 42
f()

Die Funktionen eval() und exec() haben keinen Zugriff auf die vollständige Umgebung zur Namensauflösung. Namen können im lokalen und globalen Namensraum des Aufrufers aufgelöst werden. Freie Variablen werden nicht im nächstübergeordneten Namensraum, sondern im globalen Namensraum aufgelöst. [1] Die Funktionen exec() und eval() verfügen über optionale Argumente, um den globalen und lokalen Namensraum zu überschreiben. Wird nur ein Namensraum angegeben, wird dieser für beide verwendet.

4.3. Ausnahmen

Ausnahmen dienen dazu, den normalen Kontrollfluss eines Codeblocks zu unterbrechen, um Fehler oder andere Ausnahmebedingungen zu behandeln. Eine Ausnahme wird an der Stelle ausgelöst, an der der Fehler erkannt wird; sie kann vom umgebenden Codeblock oder von jedem Codeblock behandelt werden, der den Codeblock, in dem der Fehler aufgetreten ist, direkt oder indirekt aufgerufen hat.

Der Python-Interpreter löst eine Ausnahme aus, wenn er einen Laufzeitfehler (wie beispielsweise eine Division durch Null) feststellt. Ein Python-Programm kann zudem mit der Anweisung raise explizit eine Ausnahme auslösen. Ausnahmebehandler werden mit der Anweisung try… except festgelegt. Die Klausel finally einer solchen Anweisung kann verwendet werden, um Aufräumcode anzugeben, der die Ausnahme nicht behandelt, sondern unabhängig davon ausgeführt wird, ob im vorangehenden Code eine Ausnahme aufgetreten ist oder nicht.

Python verwendet das „Termination“-Modell der Fehlerbehandlung: Ein Ausnahmebehandler kann zwar feststellen, was passiert ist, und die Ausführung auf einer übergeordneten Ebene fortsetzen, aber er kann die Fehlerursache nicht beheben und den fehlgeschlagenen Vorgang nicht wiederholen (außer durch erneutes Ausführen des fehlerhaften Codeabschnitts von Anfang an).

Wird eine Ausnahme überhaupt nicht abgefangen, bricht der Interpreter die Ausführung des Programms ab oder kehrt zu seiner interaktiven Hauptschleife zurück. In beiden Fällen gibt er einen Stack-Traceback aus, es sei denn, es handelt sich um die Ausnahme SystemExit .

Ausnahmen werden anhand von Klasseninstanzen identifiziert. Die Klausel except wird je nach Klasse der Instanz ausgewählt: Sie muss auf die Klasse der Instanz oder auf eine nicht-virtuelle Basisklasse derselben verweisen. Die Instanz kann vom Handler empfangen werden und zusätzliche Informationen über die Ausnahmebedingung enthalten.

Bemerkung

Ausnahmemeldungen sind nicht Teil der Python-API. Ihr Inhalt kann sich von einer Python-Version zur nächsten ohne Vorwarnung ändern, weshalb sich Code, der unter mehreren Versionen des Interpreters ausgeführt wird, nicht darauf verlassen sollte.

Siehe auch die Beschreibung der Anweisung try im Abschnitt Die try Anweisung und der Anweisung raise im Abschnitt Die raise Anweisung.

Fußnoten