Datum:
Hi, mit folgendem Python-Programm wehalte ich den Fehler
Traceback (most recent call last):
File "foo.py", line 21, in <module>
process (line)
File "foo.py", line 9, in process
if section == "":
UnboundLocalError: local variable 'section' referenced before assignment |
Das Programm ist:
import fileinput
import re
pat_section = re.compile ("Disassembly of section (.*):")
section = ""
def process (line):
if section == "":
return
match = re.search (pat_section, line)
if match:
section = match.group(1)
print "Section " + section
return
return
for line in fileinput.input():
process (line)
|
So wie ich die Python-Doku verstehe, ist section doch global? Wiese kommt dennoch ein Fehler, und wie behebe ich den? pat_section wird ja auch global definiert und in process() zugegriffen. Total unlogisch das alles :-(( Ohne die Zeile "section = match.group(1)" gibt es keinen Fehler, obwohl section dann auch referenziert wird.
Datum:
def process (line):
global section
Datum:
Ok, danke für die Noob-Hilfe :-) Was ich nicht verstehe, ist daß es keinen Fehler für die andere Variable pat_section gibt. Die wird doch auch goobal angelegt und lokal zugegriffen?
Datum:
Ich denke mal, weil an section in der Funktion was zugewiesen wird. Daher wird sie als lokale Variable angelegt. Da du aber davor schon aus der Variable liest, bekommst du die Fehlermeldung. pat_section wird dagegen nur gelesen, kann also keine lokale Variable sein. Klingt zwar etwas obskur, aber so sind Skriptsprachen eben.
Datum:
Johann L. schrieb: > Was ich nicht verstehe, ist daß es keinen Fehler für die andere Variable > pat_section gibt. Die wird doch auch goobal angelegt und lokal > zugegriffen? Ich (als jemand, der auch kein Python kann) interpretiere das so, dass das "global" wohl nur dann gebraucht wird, wenn es ansonsten zu Mehrdeutigkeiten kommen kann. "section = match.group(1)" kann ja anscheinend sowohl eine Zuweisung an eine existierende Variable sein, wie auch das Anlegen einer neuen Variable bedeuten. Wenn eine Variable jedoch lediglich gelesen wird (wie beim Funktionsaufruf oder auch dem if), dann muss sie ja bereits existieren, und wenn sie nicht lokal existiert, wird halt automatisch global gesucht.
Datum:
Hier ist der Teil Sprachreferenz, der sich mit solchen Dingen beschäf- tigt: http://docs.python.org/reference/executionmodel.ht... Die entscheidende Stelle darin: "If a name is bound in a block, it is a local variable of that block." Bei dir wird section im Block process durch section = match.group(1) gebunden, also ist section in process lokal und das auch schon vor der Bindung. Deswegen ist das Lesen der Variable in if section == "": ein Fehler. Aber wie schon geschrieben wurde, löst die Deklaration global section das Problem.
Datum:
Yalu X. schrieb: > Hier ist der Teil Sprachreferenz, der sich mit solchen Dingen beschäf- > tigt: > > http://docs.python.org/reference/executionmodel.ht... Genau das hab ich nach dem Fehler gelesen, aber da steht: >> Names refer to objects. Names are introduced by name binding >> operations. Each occurrence of a name in the program text refers >> to the binding of that name established in the innermost function >> block containing the use. >> >> A block is a piece of Python program text that is executed as a unit. >> The following are blocks: a module, a function body, [...] Der "innermost block" ist hier doch das Modul, weil section auf Modulebene eingeführt wird? Oder wo steh ich aufm Schlauch? > Die entscheidende Stelle darin: > > "If a name is bound in a block, it is a local variable of that block." > > Bei dir wird section im Block process durch > > section = match.group(1) > > gebunden, Der innermost block ist nicht das Modul? Wieso dann "innermost", wenn die Variable ausserhalb davon vorkommt? Ansonsten kann man sich die Definition auch sparen, da Tautologie...
Datum:
Durch die Zuweisung wird die Variable an den innersten Block gebunden. Immer. Auch wenn sie bereits in einem umgebenden Block definiert ist wird dieser Name an den Block gebunden. Und in process hast du eine Zuweisung an "section", also ist "section" in diesem Block IMMER das lokale section und das äußere "section" wird ausgeblendet.
Datum:
Johann L. schrieb: > Der innermost block ist nicht das Modul? > Wieso dann "innermost", wenn die Variable ausserhalb davon vorkommt? Ja, die Spezifikation ist an dieser Stelle vielleicht etwas missver- ständlich formuliert, ist aber folgendermaßen zu interpretieren: Die Variable section wird an zwei Stellen im Programm gebunden, einmal auf Modulebene:
section = "" |
und einmal in der Funktion process :
section = match.group(1)
|
An zwei weiteren Stellen im Programm wird section referenziert:
if section == "":
|
und
print "Section " + section
|
Beide liegen in der Funktion process. Für sie ist der "innermost function block containing the use" deswegen die Funktion process und die Referenzierung bezieht sich damit auf die Bindung der lokalen Variable. Dabei spielt es keine Rolle, ob die Referenzierung vor oder nach der Bindung stattfindet. Die Bindung der globale Variable section liegt außerhalb der Funktion und ist deswegen nicht "innermost". Würde section zusätzlich irgendwo auf Modulebene referenziert, wäre der "innermost function block containing the use" das Modul, und die Referenzierung bezöge sich auf die Bindung der globalen Variable. Der /process/-Block wäre zwar noch "innermore", würde aber den use (der ja auf Modulebene stattfände) nicht containen.
Datum:
Yalu X. schrieb: > Beide liegen in der Funktion process. Für sie ist der "innermost > function block containing the use" deswegen die Funktion process und > die Referenzierung bezieht sich damit auf die Bindung der lokalen > Variable. [...] > > Würde section zusätzlich irgendwo auf Modulebene referenziert, wäre > der "innermost function block containing the use" das Modul, und die > Referenzierung bezöge sich auf die Bindung der globalen Variable. Eigentlich würde ich für globale Variablen gerne an einer Stelle sagen, daß sie global sind, und nicht in jeder Funktion, die Informationen zusammenträgt und in einem globalen Status merkt. Wenn auf Modulebene, also ausserhalb der Funktion, ein Use erfolgt, etwa: > section = "" > section = section so hilft das auch nicht. In process ist section immer noch lokal und bedarf des "global". Ein global auf Moduleben hat keinen Einfluss. Oder verwende ich einen fehlerhafte Python-Version? Ist 2.6.
Datum:
Johann L. schrieb: > Eigentlich würde ich für globale Variablen gerne an einer Stelle > sagen, daß sie global sind, und nicht in jeder Funktion, die > Informationen zusammenträgt und in einem globalen Status merkt. Ist aber halt nicht so. Nimm ein globales Objekt und speicher Kram in dessen Eigenschaften wenn du das nachbilden willst. Johann L. schrieb: > Oder verwende ich einen fehlerhafte Python-Version? Ist 2.6. Sie verhält sich wie in der Spezifikation, wieso sollte sie fehlerhaft sein?
Datum:
Johann L. schrieb: > Eigentlich würde ich für globale Variablen gerne an einer Stelle > sagen, daß sie global sind, und nicht in jeder Funktion, die > Informationen zusammenträgt und in einem globalen Status merkt. Eine solche Möglichkeit gibt es aus gutem Grund nicht: Man würde dadurch nämlich alle Funktionen beeinflussen, die zufälligerweise eine lokale Variable namens section verwenden. Der Blackbox-Charakter einer Funk- tion würde dadurch verloren gehen. > Wenn auf Modulebene, also ausserhalb der Funktion, ein Use erfolgt, > etwa: > >> section = "" >> section = section > > so hilft das auch nicht. Nein, ich habe das oben anders gemeint: Das Lesen der Variable auf Modulebene greift nicht auf die lokale Variable in process zu, sondern auf die globale (was ja auch naheliegend ist). An der Lokalität der Variable in process ändert das aber nichts. Dieser etwas ungewohnte Umgang mit globalen Variablen kommt daher, dass in Python — anders als in C — Variablen normalerweise nicht deklariert werden. In C "deklariert" man eine Variable innerhalb einer Funktion de facto dadurch als global, dass man ihre Deklaration weglässt, wodurch eine Deklaration des gleichen Namens außerhalb der Funktion wirksam wird. In Python kann man die Variablendeklaration nicht weglassen, da keine existiert. Also muss man den umgekehrten Weg beschreiten und eine Deklaration hinzufügen, nämlich genau die "global"-Deklaration. Wenn Funktionen öfters Daten über globale Variablen austauschen, ist zu überlegen, ob man sie nicht in eine gemeinsame Klasse packt und aus der globalen Variable eine Member-Variable macht. Das löst das Problem sauberer als eine Unzahl von global-Deklarationen. Wie in den meisten Programmiersprachen sind nämlich auch in Python globale Variablen nicht so gerne gesehen :)
Datum:
Ich würde empfehlen ein paar Bücher über Compiler-/Interpreterbau zu lesen. Im speziellen über Lokalität von Bezeichnern. Dann versteht man die Ansätze doch sehr schnell. Also dass Warum und wie, Nachteile und Vorteile... Ist zwar kein "must have" aber schaden kann sowas auch nicht :)