Hi, mit folgendem Python-Programm wehalte ich den Fehler
1
Traceback (most recent call last):
2
File "foo.py", line 21, in <module>
3
process (line)
4
File "foo.py", line 9, in process
5
if section == "":
6
UnboundLocalError: local variable 'section' referenced before assignment
Das Programm ist:
1
import fileinput
2
import re
3
4
pat_section = re.compile ("Disassembly of section (.*):")
5
6
section = ""
7
8
def process (line):
9
if section == "":
10
return
11
12
match = re.search (pat_section, line)
13
if match:
14
section = match.group(1)
15
print "Section " + section
16
return
17
18
return
19
20
for line in fileinput.input():
21
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.
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?
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.
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.
Hier ist der Teil Sprachreferenz, der sich mit solchen Dingen beschäf-
tigt:
http://docs.python.org/reference/executionmodel.html#naming-and-binding
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.
Yalu X. schrieb:> Hier ist der Teil Sprachreferenz, der sich mit solchen Dingen beschäf-> tigt:>> http://docs.python.org/reference/executionmodel.html#naming-and-binding
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...
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.
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:
1
section = ""
und einmal in der Funktion process :
1
section = match.group(1)
An zwei weiteren Stellen im Programm wird section referenziert:
1
if section == "":
und
1
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.
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.
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?
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 :)
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 :)