UnboundLocalError

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
schappenberg
User
Beiträge: 11
Registriert: Sonntag 18. Oktober 2015, 23:12

Hallo,

bitte um Hilfe bei folgendem Problem. Folgend ein Auszug aus meinem Programm:

Code: Alles auswählen

import datetime
import sqlite3

def zeit():
    try:
        wetterdb = sqlite3.connect('/home/Dokumente/wetter.db')
        cur=wetterdb.cursor()
        cur.execute("SELECT * FROM wetterdaten WHERE ROWID = (SELECT MAX(ROWID) FROM wetterdaten)")
        for datensatz in cur:
            datum_now=datetime.datetime.strptime(datensatz[0], '%Y-%m-%d %H:%M:%S.%f')
            temp_now=datensatz[1]/10.0
            humity_now=datensatz[2]/10.0
            windspeed_now=datensatz[3]/10.0
            rain_now=datensatz[4]
            press_at_sea_now=datensatz[5]/100.0
        dateString=datum_now.strftime("%d.%m.%Y")
        timeString=datum_now.strftime("%H:%M")
    except sqlite3.Error as e:
        datum_now=str(e)
    except Exception as e:
        print(str(e))
    finally:
        wetterdb.close()
        
...
Beim Ausführen vom Code bekomme ich folgende Meldung mit Verweis in den "finally" Block:

Code: Alles auswählen

 File "/test/app.py", line 48, in zeit
  wetterdb.close()
UnboundLocalError: local variable 'wetterdb' referenced before assignment
Ich versteh leider nicht was da nicht passt, kann mir das bitte jemand erklären. Entferne ich die ganzen try/except/finally Blöcke funktioniert es ja, also vermute ich ein Verhalten so als wären die try/except/finally Blöcke wie eine eigene Funktion zu sehen, nur wie kann ich dann die Datenbank im finally Block schließen?

Danke vielmals
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

In `finally` benutzt Du `wetterdb`, das muß aber nicht definiert sein, wenn in der ersten Zeile des try-Blocks ein Fehler auftritt.

Wenn Du eine Abfrage hast, die exakt einen Eintrag als Antwort hat, dann ist eine for-Schleife sehr verwirrend.
deteString und timeString halten sich nicht an die Namenskonvention. Diese Variablen sollten sowieso nicht existieren, weil man erst bei der Ausgabe die Ausgabestrings generiert.

Nach einem Fehler sind die meisten der Variablen nicht definiert, es ist also keine sinnvolle Weiterverarbeitung möglich. `datum_now` ist einmal ein String mit einer Fehlermeldung einmal ein Datetime-Objekt.
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

In einem try-Block sollte so wenig Code wie möglich stehen, am besten nur eine Zeile. Bei einer Schleife würde ich eher das Exception-Handling nach innen packen, d.h. so vorgehen:

Code: Alles auswählen

for spam in spams:
    try:
        do_something(spam)
    except SomeError as error:
        # Error handling
Oder alternativ einen größeren Codeabschnitt in eine Funktion auslagern und die dann in einem try-Block aufrufen.

Ansonsten hat man einfach zu viele Namen, die im Fehlerfall nicht existieren. Und je mehr Namen dort definiert werden sollen um so schwieriger wird das Debugging bei auftretenden Exceptions.
schappenberg
User
Beiträge: 11
Registriert: Sonntag 18. Oktober 2015, 23:12

@Sirius3: 1) o.k., das ist verständlich, nur wie kann ich dann auf alle Fälle die Datenbankverbindung schließen? Also ohne try/finally sonder ev. mit einer if Abfrage ob wetterdb existiert und wenn ja dann schließen?
2) die Hinweise mit dateString und timeString werde ich berücksichtigen, Danke
3) das mit der Fehlermeldung war nur ein Versuch um einen Fehler drauf zu kommen, hab ich vergessen wieder umzustellen...
@snafu: Danke für die Hinweise

generell: ist der try/except/finally Block hier überhaupt sinnvoll oder würdet ihr den einfach ganz weg lassen?
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man danach nicht sinnvoll weiterarbeiten kann, weil Variablen fehlen, dann ist ein except-Block unsinnig, trotzdem kann es sinnvoll sein, in einem finally-Block eine bestehende Verbindung zu schließen.

Ein try-Block sollte auch nur das nötigste umschließen, der Fehler tritt bei Dir ja bei connect auf, dieser Fehler ist also anders zu behandeln als wenn die Verbindung schon hergestellt ist, und Du dann im finally-Block die Verbindung schließen mußt.
Also zumindest das connect gehört vor den try-Block.

Besser ist es mit `with` zu arbeiten, eventuell zusammen mit contextlib.closing, um zu garantieren, dass etwas wieder geschlossen wird, ohne dass man ein try-finally braucht.
Antworten