Forum: PC-Programmierung Python: globale/lokale Variablen?


von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Schlange (Gast)


Lesenswert?

def process (line):
     global section

von hscade (Gast)


Lesenswert?


von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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?

von Rolf M. (rmagnus)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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...

von hmmmm (Gast)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von hmmmm (Gast)


Lesenswert?

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?

von Yalu X. (yalu) (Moderator)


Lesenswert?

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 :)

von endurance (Gast)


Lesenswert?

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 :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.