Seite 1 von 1
Erklärbar oder Namensraum-Bug?
Verfasst: Samstag 12. November 2011, 23:19
von mutetella
Hallo,
gibt es dafür eine Erklärung:
Code: Alles auswählen
>>> foo = []
>>> def ok():
... print(id(foo))
... foo.append(1)
...
>>> def strange():
... print(id(foo))
... foo.append(2)
... foo += [2]
...
>>> id(foo)
36658712
>>> ok()
36658712
>>> foo
[1]
>>> strange()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in strange
UnboundLocalError: local variable 'foo' referenced before assignment
mutetella
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Samstag 12. November 2011, 23:58
von BlackJack
@mutetella: Erklärbar. Die Erklärung steht doch im Grunde in der Ausnahme.
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Sonntag 13. November 2011, 00:36
von mutetella
Erklärbar??
Was genau macht den 'strange()' anderes als 'ok()'? Wenn die Ausnahme bei 'foo += [2]' auftreten würde..., wobei auch das eigenartig wäre... wenn da 'foo = foo + [2]' stünde, könnte ich mir das noch dadurch erklären, dass 'foo' danach auf eine andere Liste verweist... dann allerdings dürfte die Ausnahme nicht schon beim Versuch, die id abzurufen, erscheinen... :K
Was will mir die Ausnahme denn sagen? 'foo' muss vor seiner Verwendung auf ein Objekt verweisen. Ok. Tut es doch auch. Wäre dem nicht so, müsste 'ok()' doch dieselbe Ausnahme werfen?
Warum also kann 'ok()' auf 'foo' zugreifen, wenn es 'append()' verwendet, 'strange()' aber nicht, wenn es '__iadd__()' verwendet?
mutetella
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Sonntag 13. November 2011, 03:12
von fsck
Ein Name muss bevor er referenziert werden kann, erst an etwas gebunden werden. Ein Name in einem inneren Block verdeckt den Namen im äußeren Block. Die Sichtbarkeit von Namen wird statisch festgelegt, noch vor der Ausführung eines Blockes. (Ein Block ist ein Modul, eine Funktion, eine Klasse)
Du bindest im Block der Funktion 'strange()' den Namen 'foo', welcher den äußeren Namen verdeckt, an 'foo + [2]'. Das machst du erst nach 'print(id(foo))' , also kannst du den Namen nicht schon dort verwenden. Außerdem kann 'foo = foo + [2]' nicht funktioneren, da du den Namen 'foo' ja gerade bindest.
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Sonntag 13. November 2011, 09:01
von Darii
mutetella hat geschrieben:Warum also kann 'ok()' auf 'foo' zugreifen, wenn es 'append()' verwendet, 'strange()' aber nicht, wenn es '__iadd__()' verwendet?
Weil du nirgends __iadd__ verwendest. += ist nicht äquivalent zu __iadd__. += ist ein Operator der __iadd__ aufrufen kann – sofern es existiert – und vor allem ist es eine echte Zuweisung. Die Konsequenzen hat fsck schon erklärt.
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Sonntag 13. November 2011, 12:21
von mutetella
@fsck:
Das ist mir soweit schon klar, nur: Weshalb kann dann 'ok()' auf 'foo', das außerhalb an eine Liste gebunden wurde, zugreifen?
Wenn ich 'ok()' aufrufe, existiert 'foo'. Das 'foo' aus dem äußeren Namensraum, ein anderes 'foo' gibt es ja nicht.
Wenn ich 'strange()' aufrufe, erscheint die Ausnahme, bevor ich überhaupt ein "inner-strange()"-'foo' erstelle. Und selbst wenn ich das täte, würde ich halt auf dieses 'foo' zugreifen.
Aber warum die Ausnahme an der Stelle, an der 'ok()' doch auch ohne Probleme mit 'foo' umgehen kann? Warum überhaupt eine Ausnahme? Irgendein 'foo' existiert doch allemal?
Viele Module arbeiten doch mit Konstanten, die auf Modulebene erstellt und gebunden werden und dann auch innerhalb von Funktionen ihre Gültigkeit haben. Eben das, was auch innerhalb von 'ok()' geschieht?
Wo ist die Kurve, die ich übersehen hab'?
mutetella
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Sonntag 13. November 2011, 12:31
von Leonidas
mutetella hat geschrieben:Wenn ich 'strange()' aufrufe, erscheint die Ausnahme, bevor ich überhaupt ein "inner-strange()"-'foo' erstelle. Und selbst wenn ich das täte, würde ich halt auf dieses 'foo' zugreifen.
Richtig, weil der Gültigkeitsbereich schon *vor der Ausführung des Blocks* feststeht. Und im Fall von ``strange`` ist nicht klar was ``foo`` nun ist. Ist es ein lokaler Name? Ist es ein Globaler? Im Fall von Python3: ist es ein nicht-Lokaler?
mutetella hat geschrieben:Viele Module arbeiten doch mit Konstanten, die auf Modulebene erstellt und gebunden werden und dann auch innerhalb von Funktionen ihre Gültigkeit haben. Eben das, was auch innerhalb von 'ok()' geschieht?
Wo ist die Kurve, die ich übersehen hab'?
Konstanten werden, nun, nicht aus den Funktionen zugewiesen, sonst wärens ja keine Konstanten, daher ist innerhalb der Funktionen klar das Namen die nicht im lokalen Namensraum sind, aus dem umgebenden, im Fall von ``ok`` also globalen Namensraum, stammen.
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Sonntag 13. November 2011, 13:59
von deets
mutetella hat geschrieben:
Wo ist die Kurve, die ich übersehen hab'?
Du kennst halt die scoping-Regeln von Python nicht. Python hat keine explizite Variablen-Deklaration, wie sie Sprachen wie zB Javascript oder auch Perl kennen.
Als Konsequenz daraus geht Python 2 zur Bestimmung des Scopes eines Namens in der statischen Analyse des Codes beim ersten ausfuehren so vor:
- ein Name auf modul-Ebene ist natuerlich (modul)-global
- ein Name in einer Funktion, der auf der linken Seite einer *zuweisung* auftaucht, ist Funktions-lokal. Also zb sowas hier:
- ein Name, der hinter dem global-statement auftaucht ist global
Und daher kommt auch dein "Problem". In strange taucht foo als linker Teil einer Zuweisung auf (implizit, durch das +=), und damit macht Python das bereits zur Syntaxanalyse zu einem Funktions-lokalen Namen. Womit es dann auch gleich meckern kann, dass du den schon vor seiner Einfuehrung benutzt.
Dein ok() funktioniert, weil foo dort nichts zugewiesen wird, sondern das davon referenzierte Objekt *modifiziert*.
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Montag 14. November 2011, 10:24
von mutetella
Vielen Dank für Eure guten Erklärungen... damit hab's dann auch ich kapiert

!
Dass Python bereits vor der Ausführung einer Funktion die Synthax prüft, wusste ich nicht.
Was würdet ihr mir zur Lösung der beiden folgenden Probleme raten:
Um ein erweitertes Eingabefeld, quasi ein 'ext_input()', zu realisieren, gehe ich wie folgt vor:
Code: Alles auswählen
___
| stdin: '' -> warte
| Tastatureingabe: 'a'
| ___
___
|stdin: 'a' -> übersetze Zeichen
| lese 'a', übersetze als 'a', zeige 'a' an
| sende '\033[?6n'
| __
___
|stdin: '\x1b[?20;1R' -> übersetze Zeichen
| lese '\x1b' bis 'R', übersetze als (20, 1)
| __
___
|stdin: '' -> warte
| Eingabe aus Zwischenspeicher: 'wort'
| __
___
|stdin: 'wort\x1b[?20;2R' -> übersetze Zeichen
| lese 'w', übersetze als 'w', zeige 'w' an
| sende '\033[?6n'
| __
___
|stdin: 'ort\x1b[?20;2R\x1b[?20;3R' -> übersetze Zeichen
| lese 'o', übersetze als 'o', zeige 'o' an
| sende '\033[?6n'
| __
___
|stdin: 'rt\x1b[?20;2R\x1b[?20;3R\x1b[?20;4R' -> übersetze Zeichen
| lese 'r', übersetze als 'r', zeige 'r' an
| sende '\033[?6n'
| __
...
Nachdem also etwas aus dem Zwischenspeicher eingefügt wird (oder auch dann, wenn Tasten sehr, sehr schnell hintereinander eingetippt(-trommelt) werden) erhält man erst wieder einen xterm-Report, wenn die Zeichen zuvor abgearbeitet sind.
Mein Ansatz:
- Alle Zeichen bis zum xterm-Report auslesen, den Report auswerten und die zwischengespeicherten Zeichen dann wie 'stdin' behandeln und danach wieder auf 'stdin' wechseln.
Mit anderen Worten: Zwischen jedes anzeigbare Zeichen einen xterm-Report einfügen. - Auf die ständige (teure) xterm-Abfrage verzichten, die Koordinaten einmal abfragen und intern aktuell halten.
Wie auch immer ich mich entscheide, ich muss entweder den Zwischenspeicher oder die Koordinaten auf Modulebene ablegen.
Folgende Möglichkeiten fallen mir ein:
- Ich verzichte auf Zuweisungen innerhalb der Funktionen, die Zwischenspeicher und/oder Koordinaten aktualisieren.
- Ich verwende ein dictionary.
- Ich verwende zum Zwischenspeichern ein "echtes" file.
Ich denke mal, die Cursorposition einmalig abzufragen, intern aktuell zu halten und dafür ein dictionary zu verwenden ist am sinnvollsten.
Was meint ihr?
mutetella
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Montag 14. November 2011, 10:52
von Leonidas
mutetella hat geschrieben:Was meint ihr?
Ich meine dass das eine komplett andere Frage ist und einen eigenen Thread verdient :p
Re: Erklärbar oder Namensraum-Bug?
Verfasst: Montag 14. November 2011, 11:34
von mutetella
Ok, da hast Du Recht...
Für mein Cursorthema habe ich also einen
neuen Thread geöffnet.
mutetella hat geschrieben:Wie auch immer ich mich entscheide, ich muss entweder den Zwischenspeicher oder die Koordinaten auf Modulebene ablegen.
Folgende Möglichkeiten fallen mir ein:
* Ich verzichte auf Zuweisungen innerhalb der Funktionen, die Zwischenspeicher und/oder Koordinaten aktualisieren.
* Ich verwende ein dictionary.
* Ich verwende zum Zwischenspeichern ein "echtes" file.
Das würde mich dennoch interessieren...
Wie könnte ich solche Informationen ohne Verwendung einer Klasse oder dem mühsamen weiterreichen von Funktion zu Funktion ablegen?
mutetella