Einstellungen in Datei speichern & importieren

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

Hallo,

ich brauche zur Zeit für ein Programm die Möglichkeit, verschiedene Werte zu speichern und wieder einzulesen. Ich habe mich dafür entschieden, die Daten einfach in einer CSV-Datei abzulegen.

Code: Alles auswählen

import sys
try:
    Settings = open("Programm-Einstellungen.csv","w")
except:
    print("Öffnen der Datei fehlgeschlagen!")
    sys.exit(0)

Dezimalzahl = int(input("Genauigkeit: "))
Ausgabedatei = str(input("Name der Ausgabedatei: "))
# CSV-Datensatz erstellen
Genauigkeit = ["Dezimalzahl", int(Dezimalzahl)]
Settings.write(str(Genauigkeit[0]) + ";" + str(Genauigkeit[1]) + "\n")
Settings.write(str("Ausgabedatei") + ";" + str(Ausgabedatei) + "\n")
Settings.close()
Dezimalzahl steht für die Genauigkeit in Nachkommastellen, Ausgabedatei für den Standardnamen eines Protokolls des Programms (beides funktioniert wunderbar, aber ich will dem Nutzer nicht aufzwingen das jedes mal wieder neu einzugeben).


Zum import habe ich folgenden Codeschnipsel:

Code: Alles auswählen

 try:
        Settings = open("Programm-Einstellungen.csv")
    except:
        print("Öffnen der Datei fehlgeschlagen!")
        sys.exit(0)

    Datei_Inhalt = Settings.read() #Liest Datei ein
    Settings.close() #Schließt Datei
    zeilenliste = Datei_Inhalt.split(chr(10)) #Zeilen aufteilen
    Einstellungen2d = [] #Leere Liste, die im Nachfolgenden mit den Werten befüllt wird (2d Liste)
    for x in zeilenliste:
        if x:
            templiste = x.split(";")
            Einstellungen2d.append([str(templiste[0]), str(templiste[1])])
    Einstellungen_normal = [Einstellungen2d[0][0], Einstellungen2d[0][1], Einstellungen2d[1][0], Einstellungen2d[1][1]] #Liste "Einstellungen2d" wird in eine Dimension konvertiert
Das ganze an sich funktioniert eigentlich recht gut, nur habe ich jetzt das Problem, dass wenn ein Nutzer bspw. keinen neuen Ausgabenamen wählen will aber den Wert von "Dezimalzahl" ändern will, dass Programm wohl eher unbrauchbare werte liefert.

Kann mir jemand sagen, wie ich also überprüfen kann, welche Werte gesetzt wurden und diese Werte dann als Variable im Programm einsetzen kann? (für default-Werte könnte man ja bspw. per if/else verzweigung einfach keine variable setzen, hab aber grad nichts dienliches vor meinem geistigen Auge)

Lg heiliga horsd


edit: Wäre es auch Möglich, die Daten als Funktionsparameter zu übergeben? Und wie müsste ich dann Code #1 und Code #2 abändern, dass es da keine Konflikte gibt?
Redprince
User
Beiträge: 128
Registriert: Freitag 22. Oktober 2004, 09:22
Wohnort: Salzgitter
Kontaktdaten:

[mod]ConfigParser[/mod] existiert ;)
I am not part of the allesburner. I am the [url=http://allesburner.de]allesburner[/url].
heiliga horsd

Wow, das kannte ich gar nicht, vielen dank!
Ich werd mich da mal einlesen, und falls es Probleme gibt, mich nochmal melden.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo!

Mit csv-Dateien selber verwalten möchtest du dich auch nicht herumschlagen, verwende besser (wenn du sie denn mal einsetzt) das [mod]csv[/mod]-Modul.

Ein paar Hinweise zu deinem Code habe ich auch noch für dich:
- Benutze *niemals* ein except ohne das du die abzufangenen Meldungen angibst. Dann werden wirklich alle Fehler abgefangen, was u.U. das Finden von Fehlern unglaublich erschwert.
- Schau dir mal das with-Statment an, das macht das arbeiten mit Dateien einfacher
- Einen Blick in PEP 8 kannst du auch riskieren ;-)
- Denke daran, dass bei int(input(...)) möglicherweise Exceptions geworfen werden!
- str(input(...)) ist das selbe wie einfach nur input(...)
- Die Liste "Genauigkeit" kannst du dir sparen
- Eine Liste für Einstellungen ist sehr ungeschickt, da bietet sich ein Dictionary an.
- Zeile 13 ist ein wenig ungeschickt: überlege mal was passiert, wenn in der Zeile evt. Whitespace enthalten ist
- In Zeile 15 sind die str-Aufrufe natürlich auch überflüssig
- Und: was passiert bei unvollständigen Dateien?

Die Punkte benötigst du durch den configparser zwar nicht mehr alle, du kannst aber sicher trotzdem etwas daraus mitnehmen.

Bis dann
Sebastian
Das Leben ist wie ein Tennisball.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Viel eleganter wie das builtin ConfigParser finde ich die Bibliothek ConfigObj, hat eine viel angenehmere und intuitivere Syntax.
http://www.voidspace.org.uk/python/configobj.html
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Das sieht doch recht nett aus, auf den ersten Blick!

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hallo Sebastian,

ich mag nicht gern widersprechen, aber zwei Dinge möchte ich erwähnen:
EyDu hat geschrieben: - Benutze *niemals* ein except ohne das du die abzufangenen Meldungen angibst. Dann werden wirklich alle Fehler abgefangen, was u.U. das Finden von Fehlern unglaublich erschwert.
Prinzipiell hast Du recht, dass es während der Programmierung zumeist das Aufspüren von Fehlern erschwert. Es aber kategorisch auszuschließen, halte ich für übertrieben. Z.B. wenn die Art des Fehlers nicht von belang ist und jeder Fehler zu einem Abbruch führen soll, kann man das aus meiner Sicht getrost verwenden. Die Frage ist, wie man dann im except-Block damit umgeht.
EyDu hat geschrieben: - Denke daran, dass bei int(input(...)) möglicherweise Exceptions geworfen werden!
- str(input(...)) ist das selbe wie einfach nur input(...)
Das ist nicht ganz richtig. Die __builtins__-Funktion input erwartet die Benutzereingabe UND führt darauf automatisch ein eval aus! Das heißt, es wertet die Eingabe als Literal as und wandelt beispielsweise eine 15 gleich in ein Integer um. Die int und str Funktionen sind in diesem Code also überflüssig. Wenn man die Eingabe als String haben möchte, verwendet man raw_input.

Code: Alles auswählen

>>> res = input("zahl:")
zahl: 15
>>> type(res)
<type 'int'>

>>> res = raw_input("zahl:")
zahl: 15
>>> type(res)
<type 'str'>
VG,
Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hallo,
heiliga horsd hat geschrieben:ich brauche zur Zeit für ein Programm die Möglichkeit, verschiedene Werte zu speichern und wieder einzulesen. Ich habe mich dafür entschieden, die Daten einfach in einer CSV-Datei abzulegen.
Also wenn ich frei wählen könnte, würde ich eher ein dict verwenden und es mit pickle speichern und laden:

Code: Alles auswählen

>>> import pickle
>>> settings = {"value": 15}

>>> fout = open("settings.config", "wb")
>>> pickle.dump(settings, fout, protocol=2)
>>> fout.close()

>>> fin = open("settings.config", "rb")
>>> s = pickle.load(fin)
>>> fin.close()
>>> print s
{'value': 15}
Gruß,
Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Ich glaube der OP nutzt Python 3, daher ist `input` das `raw_input` aus 2.6. Deshalb ist `str(input())` sinnlos.
Ein generelles Except fängt auch sachen wie KeyboardInterrupt ab, weshalb das nicht zu empfehlen ist.

Ich glaube statt pickle würde ich json verwenden.
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

jbs hat geschrieben:Ich glaube der OP nutzt Python 3, daher ist `input` das `raw_input` aus 2.6. Deshalb ist `str(input())` sinnlos.
Irgendwie ist diese Pseudo-Vereinfachung von bekannten Spracheigenschaften die größte Hürde, die mich von einem Umstieg auf Python 3 abhält. :-(
jbs hat geschrieben:Ein generelles Except fängt auch sachen wie KeyboardInterrupt ab, weshalb das nicht zu empfehlen ist.
Ok, und wo ist das Problem?

Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Michael Schneider hat geschrieben:
jbs hat geschrieben:Ein generelles Except fängt auch sachen wie KeyboardInterrupt ab, weshalb das nicht zu empfehlen ist.
Ok, und wo ist das Problem?
Und natuerlich noch `SystemExit`.
Das Problem sollte offensichtlich sein: Es faengt eben nicht nur "eigentliche" Exceptions ab, sondern alles, das ueber Exceptions implementiert wurde. Besser ist `except Exception`.
heiliga horsd

Ja, ich verwende Python 3.1. Dass das int(input...) bei falschen Eingaben einen Fehler wirft, weiß ich, der Code ist nur zu Testzwecken da und noch nicht wirklich intergriert. Da ich mir das configparser gestern noch ein wenig angeschaut habe, kann ich schon sagen, dass es wohl für meine Zwecke ausreichend sein wird. Immerhin speichere ich keine exotischen Werte, und die Syntax von config parser ist ja auch (für meine zwecke) verständlich genug.

@EyDu: Ich entschuldige mich im vorhinein für die evtl. etwas blöde Frage, aber was ist PEP 8?

@Michael Schneider: An pickle hatte ich eigentlich gar nicht gedacht :oops:
Aber es gibt ja anscheinend eine sehr große Vielfalt an Möglichkeiten, was ja auch prinzipiell gut ist. Ich denke mit configparser habe ich eine gute wahl getroffen.

@cofi: Was ist an except Exception "besser"?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

heiliga horsd hat geschrieben:@EyDu: Ich entschuldige mich im vorhinein für die evtl. etwas blöde Frage, aber was ist PEP 8?
Der Python Styleguide: http://python.org/dev/peps/pep-0008/
heiliga horsd hat geschrieben:@cofi: Was ist an except Exception "besser"?
Es faengt die angesprochenen uneigentlichen Exceptions nicht ab. Siehe hier
heiliga horsd

Danke, den Styleguide werd ich mir sicherlich später mal durchlesen.
Also, wenn ich das richtig verstanden habe, werden dann:

+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit

nicht abgefangen, oder? Das wusste ich gar nicht, wenn mir manchmal Programme zu lange laufen breche ich sie oft mit Strg+C ab, Danke für den Hinweis!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du hast richtig verstanden.
Das Leben ist wie ein Tennisball.
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

cofi hat geschrieben:
Michael Schneider hat geschrieben:
jbs hat geschrieben:Ein generelles Except fängt auch sachen wie KeyboardInterrupt ab, weshalb das nicht zu empfehlen ist.
Ok, und wo ist das Problem?
Und natuerlich noch `SystemExit`.
Das Problem sollte offensichtlich sein: Es faengt eben nicht nur "eigentliche" Exceptions ab, sondern alles, das ueber Exceptions implementiert wurde. Besser ist `except Exception`.
Du widerlegst Dich gerade selbst.
'except Exception' fängt eben nicht alle Exceptions ab. Das kann aber zweckmäßig sein, wenn man z.B. einen Prozess sicher abschließen und nicht durch eine strg+c abbrechen lassen will. Es ist nicht immer sinnvoll, aber es kategorisch auszuschließen finde ich ein wenig übertrieben.

Wie oben gesagt: es kommt darauf an, wie die gefangene Ausnahme dann verarbeitet wird.

VG,
Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Michael Schneider hat geschrieben: Du widerlegst Dich gerade selbst.
'except Exception' fängt eben nicht alle Exceptions ab.
Das tue ich nicht, denn genau das habe ich gesagt. Und genau das ist der Grund, warum man das bevorzugen sollte.
cofi hat geschrieben:Es faengt eben nicht nur "eigentliche" Exceptions ab, sondern alles, das ueber Exceptions implementiert wurde.
War aber zugegeben etwas verwirrend.

Wenn man das Verhalten, dass du beschreibst erreichen will ist immernoch `except BaseException` besser, da es genau dokumentiert, dass das Absicht is. Darauf kann man bei einem blanken `except` eben nicht schliessen. (Ist allerdings auch etwas neuer.)
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

cofi hat geschrieben:
Michael Schneider hat geschrieben: Du widerlegst Dich gerade selbst.
'except Exception' fängt eben nicht alle Exceptions ab.
Das tue ich nicht, denn genau das habe ich gesagt. Und genau das ist der Grund, warum man das bevorzugen sollte.
Tust Du wohl, denn mein Beispiel sagte "alles abfangen, egal was es ist". Du antwortetest mit "except Exception" und schreibst dazu, dass es einige Exceptions nicht abfängt. :-)
cofi hat geschrieben:Wenn man das Verhalten, dass du beschreibst erreichen will ist immernoch `except BaseException` besser, da es genau dokumentiert, dass das Absicht is. Darauf kann man bei einem blanken `except` eben nicht schliessen. (Ist allerdings auch etwas neuer.)
Siehst Du, wieder was gelernt. :-) Die gibt es seit 2.5, hätte ich also durchaus kennen können/sollen. :D

Wobei das auch nur funktioniert, solange man keine eigenen Exceptions wirft, die nicht mit BaseException verwandt sind...

VG,
Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
heiliga horsd

Also, ich habe jetzt folgende Funktionen:

Code: Alles auswählen

def Schreiben(a,b):
    config = configparser.RawConfigParser()
    config.add_section('Programm-Settings')
    config.set('Programm-Settings', 'Ausgabedatei', b)
    config.set('Programm-Settings', 'Dezimalzahl', a)
    with open('Programm-Einstellungen.cfg', 'a') as configfile:
        config.write(configfile)

Code: Alles auswählen

def Lesen():
    config = configparser.RawConfigParser()
    config.read('Pogramm-Einstellungen.cfg')
    global Dezimalzahl
    Dezimalzahl = config.getint('Programm-Settings', 'Dezimalzahl')
    global Ausgabedatei
    Ausgabedatei = config.get('Programm-Settings', 'Ausgabedatei')
Nun soll folgende Funktion den Wert für die Genauigkeit verwenden:

Code: Alles auswählen

def KatheteBerechnen (): #Funktion berechnet Kathetenlaenge
    #Variablen: b: Kathete, c: Hypotenuse, a: errechnete Kathete
    Lesen()
    if Dezimalzahl == -1:
        Dezimalzahl = int(input ("Genauigkeit in Nachkommastellen: "))
        if Dezimalzahl < 0:
            print ("Die Nachkommastellenanzahl muss größer oder gleich 0 sein")
            return
        elif Dezimalzahl >100:
            print ("maximal 100 Nachkommastellen")
            return
    b = Decimal(str(locale.atof(input ("Kathetenlaenge:  "))))
    if NullCheck (b):
        return
    c = Decimal(str(locale.atof(input ("Hypotenusenlaenge: "))))
    if NullCheck (c):
        return
    if c <= b:
        print ("Hypotenusenlaenge kleiner als Kathetelaenge, Abbruch")
        return
    a = ((c*c)-(b*b)).sqrt().quantize(getcontext().power(Decimal('10.0'), -1 * Dezimalzahl))
Leider bekomme ich dauernd:
UnboundLocalError: local variable 'Dezimalzahl' referenced before assignment
Nun meine Fragen:
a) was mache ich falsch bzw. wie müsste das erfolgreiche auslesen aussehen?
b) wie kann ich beim configparser default-variablen setzen? (und wie überprüfe ich dann später in der funktion auf die default-variable?)
c) Tipps von eurer Seite?


Das mit den exceptions bei der Eingabe von Daten hab ich jetzt noch nicht dazugeschrieben, war mir bisher noch zu viel Arbeit ;-)
Zuletzt geändert von heiliga horsd am Freitag 22. Januar 2010, 18:00, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

heiliga horsd hat geschrieben: Nun meine Fragen:
a) was mache ich falsch bzw. wie müsste das erfolgreiche auslesen aussehen?
Du musst die Objekte auch außerhalb Deiner "Lesen()"-Funktion verfügbar machen!

Code: Alles auswählen

def get_params():
    bar = 5
    return bar

def foo(param):
    # mache was mit dem parameter
    print param

def main():
    param = get_params()
    foo(param)
überprüfe ich dann später in der funktion auf die default-variable?)
c) Tipps von eurer Seite?
PEP8 beachten!
Antworten