www.mikrocontroller.net

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


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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.

Autor: Schlange (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
def process (line):
     global section

Autor: hscade (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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?

Autor: Rolf Magnus (rmagnus)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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...

Autor: hmmmm (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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:
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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: hmmmm (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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?

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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 :)

Autor: endurance (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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 :)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net