Hallo,
ich lese gerade #ausgründen das Python-Tutorial https://docs.python.org/3/tutorial. Im Kapitel zu Klassen habe ich zwei Verständnisprobleme. Im Sinne von: was will der Autor sagen?
1. "A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace." -> was soll der Teil ab "... than an unqualified reference..." bedeuten? Also worauf bezieht sich das "unqualifiziert"?
2. Ein paar Abschnitte später kommt mehrfach "textual" bzw. "textually" vor - heißt übersetzt "textuell", macht nach meinem Verständnis aber keinen Sinn. Kann es sein, dass das hier eher "kontextbezogen" heißen soll?
Gruß, noisefloor
zwei Fragen zum Python Tutorial
- noisefloor
- User
- Beiträge: 3882
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
- __blackjack__
- User
- Beiträge: 13236
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@noisefloor: Ad 1. nur der nackte Name ohne irgendwas davor mit dem Punktoperator. Also nicht `sys.argv` oder `self.attribute`.
Ad 2. Es geht da um die „textuell aktuelle Funktion“, also der Textbereich im Quelltext der den Funktionskörper ausmacht, nicht aktuelle Funktion im Sinne von welche Funktion zur Laufzeit aktuell ausgeführt wird/aktiv ist. In dem Absatz der mit „It is important to realize that scopes are determined textually:“ wird doch genau das erklärt was „textually“ hier bedeutet.
Edit: Traditioneller heisst das übrigens lexical scope.
Ad 2. Es geht da um die „textuell aktuelle Funktion“, also der Textbereich im Quelltext der den Funktionskörper ausmacht, nicht aktuelle Funktion im Sinne von welche Funktion zur Laufzeit aktuell ausgeführt wird/aktiv ist. In dem Absatz der mit „It is important to realize that scopes are determined textually:“ wird doch genau das erklärt was „textually“ hier bedeutet.
Edit: Traditioneller heisst das übrigens lexical scope.
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
„Unqualified“ heißt, dass ein Name allein reicht, um das Objekt zu identifizieren, z. B. `a`. „Qualified“ bedeutet, dass das Objekt über Attributzugriff identifiziert wird, also z. B. `module.name` oder `self.attribute`. Das „qualifiziert“ bezieht sich darauf, dass der Name des Objektes durch einen anderen Namen „qualifiziert“ wird.
Beispiel:
„Kontextbezogen“ statt „textuell“ macht meinem Verständnis nach keinen Sinn. Da würde ich dann erwarten, dass das hier funktioniert und 42 ausgibt:
In `f` gibt es textuell kein `x` im lokalen oder einem der umschließenden Scopes. Kontextbezogen schon: `g` hat ein `x` im Scope, also könnte das in `f` gefunden werden, wenn der Kontext mit einbezogen würde. Es gibt Sprachen, in denen das genau so funktioniert (frühe LISPs, soweit ich weiß), und da wird das üblicherweise „dynamic scoping“ genannt, weil der dynamische Kontext bestimmt, ob ein Name in Scope ist oder nicht.
In Python kann man den Scope von Namen statisch (also ohne das Programm auszuführen) bestimmen, alleine indem man sich den Quelltext anguckt. Deswegen „textuell“.
Falls dich das Thema tiefer interessiert, empfehle ich Crafting Interpreters, ein Buch, das die Implementierung einer relativ Python-ähnlichen Sprache beschreibt. Zwei Abschnitte gehen im besonderen auf Scoping ein: Das Kapitel über Statements für den Scope innerhalb einer Funktion (in der dort implementierten Sprache komplizierter als in Python, weil Blöcke anders als in Python dort eigene Scopes aufmachen) und Kapitel 10 und 11 über die Implementierung von Scopes in Bezug auf verschachtelte Funktionsaufrufe und Closures.
Beispiel:
Code: Alles auswählen
a = 42
print(a) # beides unqualifiziert; a ist im innersten Scope (also lokal meist lokal); print ist im builtin-Scope
class C:
def method(self):
print("method")
other_method = method # unqualifiziert, weil der Körper der Klasse einen Scope bildet
def f(self):
method # NameError: unqualifizierter Zugriff reicht nicht, weil method nicht in einem der vier Scopes enthalten ist, die durchsucht werden
C.method # C wird unqualifiziert benutzt (funktioniert, weil C im globalen Scope enthalten ist); method wird qualifiziert benutzt, weil es ein Attribut von C ist
Code: Alles auswählen
def f():
print(x)
def g():
x = 42
f()
g()
In Python kann man den Scope von Namen statisch (also ohne das Programm auszuführen) bestimmen, alleine indem man sich den Quelltext anguckt. Deswegen „textuell“.
Falls dich das Thema tiefer interessiert, empfehle ich Crafting Interpreters, ein Buch, das die Implementierung einer relativ Python-ähnlichen Sprache beschreibt. Zwei Abschnitte gehen im besonderen auf Scoping ein: Das Kapitel über Statements für den Scope innerhalb einer Funktion (in der dort implementierten Sprache komplizierter als in Python, weil Blöcke anders als in Python dort eigene Scopes aufmachen) und Kapitel 10 und 11 über die Implementierung von Scopes in Bezug auf verschachtelte Funktionsaufrufe und Closures.
- noisefloor
- User
- Beiträge: 3882
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
ok, vielen Dank!
Was das praktisch bedeutet war mit schon klar, aber die Nomenklatur hate ich in der Form noch nicht gehört.
> Falls dich das Thema tiefer interessiert, ...
Nee, eigentlich nicht. Der Hintergrund ist ein anderer. Dazu gibt es in den kommenden Tagen / Wochen mehr Infos in einem neuen Thread.
Gruß, noisefloor
ok, vielen Dank!
Was das praktisch bedeutet war mit schon klar, aber die Nomenklatur hate ich in der Form noch nicht gehört.
> Falls dich das Thema tiefer interessiert, ...
Nee, eigentlich nicht. Der Hintergrund ist ein anderer. Dazu gibt es in den kommenden Tagen / Wochen mehr Infos in einem neuen Thread.
Gruß, noisefloor
Wobei in Python ja auch Klamotten wie so etwas möglich sind:
Ist das dann auch noch als ein textueller Ansatz zu verstehen? Also klar, man sieht immer noch, was passiert. Aber ist es hier nicht schon eine Vermischung mit dem Kontext? Natürlich schreibt man üblicherweise sein Python-Programm nicht so, aber die Sprache erlaubt es nun mal.
Code: Alles auswählen
def func():
print(x)
func.__globals__["x"] = 42
if __name__ == "__main__":
func()
@snafu: Ja, ist immer noch rein textuell. Vergleiche mit:
Es ist statisch festgelegt, in welchem Scope der Name gesucht wird. Dass z. B. der `globals`-Scope mutable ist (oder durch ein komplett anderes Dictionary ausgetauscht werden kann) ändert nichts daran, dass `print(x)` beide Namen im globalen Scope sucht.
Code: Alles auswählen
def f():
locals()["x"] = 42
print(x)
Jetzt bin ich etwas verwirrt:
In einem anderen Thread hieß es mal, Pyhton kenne keinen lexical scope:
viewtopic.php?t=57026
Sehe ich es richtig, dass es früher mal dynamisch implementiert war und jetzt zu statisch geändert wurde?
In einem anderen Thread hieß es mal, Pyhton kenne keinen lexical scope:
viewtopic.php?t=57026
Dann steht in der Dokumentation im bereits von noisefloor erwähnten Artikel:Das x in foo() und das x in undo_foo() sind nicht dasselbe x. Python kennt keinen Lexical Scope.
und ein paar Absätze weiter unten:Although scopes are determined statically, they are used dynamically. At any time during execution, there are 3 or 4 nested scopes whose namespaces are directly accessible:
Ich hab da jetzt den Überblick verloren, wann es dynamisch und wann statisch agiert, vielleicht könntet da nochmal etwas nachfüttern, das wäre super .On the other hand, the actual search for names is done dynamically, at run time — however, the language definition is evolving towards static name resolution, at “compile” time, so don’t rely on dynamic name resolution! (In fact, local variables are already determined statically.)
Sehe ich es richtig, dass es früher mal dynamisch implementiert war und jetzt zu statisch geändert wurde?
@mm96: Ich bin mir nicht sicher, welche Definition von „lexical scope“ pillmuncher in dem verlinkten Beitrag benutzt hat, weil das, was da beschrieben ist, nicht wirklich zu „Python kennt keinen Lexical Scope“ passt. Ich könnte mir am ehesten vorstellen, dass das ein Vertipper war und eigentlich dynamic scope gemeint war (weil dein Beispiel im Prinzip das gleiche ist wie mein Beispiel mit `print(x)`).
Die Verschachtelung von Scopes wird in Python statisch (textuell, lexical) ermittelt. Wenn eine Funktion textuell in einem Modul steht, ist ihr umschließender Scope der Modulscope genau dieses Moduls und nicht der des Moduls, in dem sie aufgerufen wird. Genau so bei Closures.
Wo ein Name gesucht wird, ist auch statisch festgelegt, allerdings gibt es zwei verschiedene Regeln:
Was auch immer wieder Verwirrung hervorruft, ist, dass es in Python (anders als in den meisten anderen Sprachen) keine expliziten Variablendeklarationen gibt, sondern dass eine Zuweisung immer auch eine Variable im innersten Scope anlegt und sich nie auf eine Variable in einem äußeren Scope bezieht (dafür braucht man `global` oder `nonlocal`). Das könnte pillmuncher auch gemeint haben.
Die Verschachtelung von Scopes wird in Python statisch (textuell, lexical) ermittelt. Wenn eine Funktion textuell in einem Modul steht, ist ihr umschließender Scope der Modulscope genau dieses Moduls und nicht der des Moduls, in dem sie aufgerufen wird. Genau so bei Closures.
Wo ein Name gesucht wird, ist auch statisch festgelegt, allerdings gibt es zwei verschiedene Regeln:
- In Funktionen: Wenn eine Zuweisung an den Namen im lokalen Scope existiert, wird der Name immer in genau diesem Scope gesucht (auch wenn dynamisch die Zuweisung noch gar nicht ausgeführt wurde), sonst im umschließenden (und es geht mit Regel 2 weiter). In deinem Beispiel war im lokalen Scope von `undo_foo` eine Zuweisung an `x` (weil `-=` eine Zuweisung ist), deswegen war `x` ein lokalen Name in der Funktion und nicht ein gecaptureter aus der umgebenden Funktion.
- Außerhalb von Funktionen (also auf Modulebene und im Körper von Klassen): Ein Name wird von innen nach außen in allen umschließenden Scopes gesucht und der erste gefundene Name wird genommen. Bei einer Zuweisung wird der Name in den innersten Scope eingefügt. Beispiel:
Ausgabe:
Code: Alles auswählen
a = 27 print("global", a) class C: print("in C", a) a = 42 print("in C", a) class Inner: print("in Inner", a) a = 99 print("in Inner", a) print("in C", a) print("global", a)
Dabei ist zu beachten, dass der umschließende Scope von einem Klassenscope immer der Scope des enthaltenden Moduls ist.Code: Alles auswählen
global 27 in C 27 in C 42 in Inner 27 in Inner 99 in C 42 global 27
Was auch immer wieder Verwirrung hervorruft, ist, dass es in Python (anders als in den meisten anderen Sprachen) keine expliziten Variablendeklarationen gibt, sondern dass eine Zuweisung immer auch eine Variable im innersten Scope anlegt und sich nie auf eine Variable in einem äußeren Scope bezieht (dafür braucht man `global` oder `nonlocal`). Das könnte pillmuncher auch gemeint haben.
Vielen Dank für den Tip, das ist wirklich sehr spannend zu lesen.narpfel hat geschrieben: ↑Donnerstag 4. Januar 2024, 16:05 Falls dich das Thema tiefer interessiert, empfehle ich Crafting Interpreters, ein Buch, das die Implementierung einer relativ Python-ähnlichen Sprache beschreibt.