Aufgabenverwaltung

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.
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Ich glaube, ich habe nicht verstanden, was du meinst. Meine Änderung:

Code: Alles auswählen

 with open("aufgaben.txt", "w") as aufgaben_datei:
      try:
 -        AUFGABEN = load(aufgaben_datei)
 -    except:
 -        AUFGABEN = dict()
 +        aufgaben = load(aufgaben_datei)
 +    except IOError:
 +        aufgaben = dict()
Leider funktioniert es immer noch nicht, obwohl ich doch eigentlich nur abfange, wenn die Datei leer ist.
Hier sieht man schön warum nackte ``except``\s ohne konkrete Ausnahmen keine gute Idee sind. Du rennst wegen einem Programmierfehler immer in das ``except``
Welcher Fehler ist das?
Es wäre übrigens praktischer wenn Du beim Verlinken Deines Quelltextes nicht immer wieder das Master-Tag verwenden würdest, sondern einen Link auf die konkrete Revision die gemeint ist.
Wie geht das?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Xfd7887a hat geschrieben:Welcher Fehler ist das?
Nimm das except mal raus ;-)
Das Leben ist wie ein Tennisball.
BlackJack

@Xfd7887a: Die Änderung behandelt jetzt alles was ein `IOError` ist, das ist mehr als nur das die Datei nicht existiert. Der Fall das die Datei nicht existiert, kann nebenbei gesagt innerhalb des ``try``/``except`` überhaupt gar nicht auftreten weil Du dort bereits ein geöffnetes Dateiobjekt vor dem betreten hast. Dann *muss* die Datei existieren, denn wie könnte man sonst so ein Objekt haben!?

Gib der Ausnahme in dem ``except`` noch einen Namen und gib das Ausnahmeobjekt dann doch einfach mal mit ``print`` aus, dann siehst Du ja was die Nachricht von dem Objekt sagt.

Zum verlinken: Du könntest zum Beispiel über die History gehen und da beim gewünschten Commit-Stand auf „Browse code →” klicken um zum Stand der Datei zu dem konkreten Commit zu kommen. So bin ich auf den Link in meinem letzten Beitrag gekommen.
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Ok, danke. Werde mich damit auseinandersetzen :D
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Die Ausgabe ist:

Code: Alles auswählen

File not open for reading
Das verstehe ich nicht, ich habe die Datei doch geöffnet.
Der Fall das die Datei nicht existiert, kann nebenbei gesagt innerhalb des ``try``/``except`` überhaupt gar nicht auftreten weil Du dort bereits ein geöffnetes Dateiobjekt vor dem betreten hast.
Ja, die Datei ist immer da. Mir geht's im Moment darum, ob sie gefüllt oder leer ist.
BlackJack

@Xfd7887a: Da steht nicht die Datei wäre nicht geöffnet sondern sie ist nicht *zum lesen* geöffnet. Man kann aus einer Datei die man zum schreiben öffnet, nicht lesen. Und wenn man eine zum schreiben öffnet, wird sie geleert — das heisst was Du ganz am Anfang machst, ist die Daten zu löschen die Du eigentlich einlesen möchtest.
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Danke :D
Habe das jetzt so:

Code: Alles auswählen

def datei_laden():
    datei = open("aufgaben.txt")
    aufgaben = pickle.load(datei)
    return aufgaben


def in_datei_schreiben(daten):
    datei = open("aufgaben.txt", "w")
    pickle.dump(daten, datei)
    datei.close()
und so:

Code: Alles auswählen

try:
    aufgaben = datei_laden()
except IOError:
    in_datei_schreiben(dict())
    aufgaben = datei_laden()
gelöst. Sicherlich ist das ziemlich umständlich, aber es funktioniert :D
BlackJack

@Xfd7887a: Da wird beim Laden die Datei wieder nicht geschlossen. Warum verwendest Du in den beiden Funktionen nicht die ``with``-Anweisung?

Und warum jetzt `pickle` statt `json`?
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Stimmt, das habe ich übersehen:

Code: Alles auswählen

def datei_laden():
    with open("aufgaben.txt") as datei:
        aufgaben = pickle.load(datei)
    return aufgaben


def in_datei_schreiben(daten):
    with open("aufgaben.txt", "w") as datei:
        pickle.dump(daten, datei)
Weil das die bevorzugte Variante für Python zu sein scheint. Aber eigentlich ist das Format ja egal.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Xfd7887a hat geschrieben:Weil das die bevorzugte Variante für Python zu sein scheint.
Wäre ja mal interessant, was "die bevorzugte" Variante wirklich ist, aber Pickle IMHO nicht.
Xfd7887a hat geschrieben:Aber eigentlich ist das Format ja egal.
Also pickle hat für mich zwei entscheidende Nachteile: Zum einen sind pickle-Dateien nicht menschenlesbar, zum anderen darf sich, wenn Du pickle zum Speichern von Klassenexemplaren verwendest, an deren Struktur nichts ändern. Ok, letzteres betrifft Dich nicht, wollte ich aber erwähnt haben.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Btw.: für pickle solltest Du die Dateien für binäres Lesen und Schreiben öffnen.
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Code: Alles auswählen

Zum einen sind pickle-Dateien nicht menschenlesbar
Habe ich auch gerade gesehen. Spielt für mich jetzt keine Rolle, aber gut, dass ich es für weitere Projekte weiß. Den anderen Punkt verstehe ich nicht, ich fange erst mit Klassen an :D.

# Edit: Apropos Klassen: Würde es Sinn machen, mein Programm mit Klassen auszudrücken? Wenn ich irgendwann ne GUI einprogrammiere, werde ich sicherlich nicht drum 'rum kommen.
BlackJack

@mutetella: Ergänzend zu mutetella's Anmerkungen: `pickle` ist auf Python beschränkt. (Falls es doch eine Bibliothek für eine andere Programmiersprache geben sollte: JSON-Bibliotheken gibt es für *sehr* viele Programmiersprachen.) Man könnte zum Beispiel zur Anzeige der Aufgaben eine Webseite mit JavaScript schreiben, die diese Datei nachlädt und dann anzeigt. Die HTML-Datei braucht man dann nur einmal auf den Webserver hochladen und zum aktualisieren bräuchte man nur noch die JSON-Datei erneut hochladen.

Bei diesem Programm ist das mit dem ”menschenlesbar” vielleicht noch nicht so interessant, aber es kann manchmal zur Fehlersuche hilfreich sein wenn man sich das gespeicherte Ergebnis ausserhalb der eigenen Anwendung anschauen kann.

Ich nutze `pickle` nur noch für kurzfristig gespeicherte Daten, zum Beispiel für Caches, oder zum serialisieren von Daten für die Übertragung zu anderen Python-Programmen. Oft auch indirekt weil entsprechende Bibliotheken das halt nutzen.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Xfd7887a hat geschrieben:Den anderen Punkt verstehe ich nicht, ich fange erst mit Klassen an.
Das heißt, dass Du zwischen Speichern und Laden von Klassenexemplaren nichts an einer Klasse ändern darfst. Wenn Du also aus irgendeinem Grund der Klasse noch zusätzliche Attribute hinzufügst oder bestehende wegnimmst, kannst Du mit den bereits gepickelten Daten erstmal nichts mehr anfangen, da diese in die geänderte Klassenstruktur nicht mehr hineinpassen, da sie ja von den geänderten Attributen nichts wissen. In einem solchen Fall muss man also die alten Daten erstmal in die alte Klassenstruktur laden, diese Exemplare dann in die neue Klassenstruktur konvertieren und dann erst wieder abspeichern. Sehr mühsam und eigentlich unnötig, wenn man auf pickle im Produktiveinsatz verzichtet, da es ja eben ausreichend Ersatz gibt, z. B. eben json oder gleich 'ne Datenbanklösung, wenn das denn nötig ist.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Ok, das habe ich verstanden. Also ist json im Allgemeinen die bessere Wahl.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Xfd7887a hat geschrieben:Apropos Klassen: Würde es Sinn machen, mein Programm mit Klassen auszudrücken?
Ich finde ja. Momentan befinden sich Deine Daten `aufgaben` auf Modulebene, wo Sie eigentlich nicht hingehören. Wenn Du dafür eine Klasse `Tasks` (ich bevorzuge ja englische Namen) erstellst fände ich das übersichtlicher. Zudem wäre dann zusammen, was zusammengehört: Die Attribute einer Aufgabe wie Fach, Datum etc. und die Methoden (Funktionen), die Du darauf anwendest. Zum Beispiel:

Code: Alles auswählen

class Task(object):
    def __init__(self, subject, date, theme, grade):
        self.subject = subject
        self.date = date
        self.theme = theme
        self.grade = grade

    def __str__(self):
        return 'Task: {s} {d} {t} {g}'.format(
            s=self.subject, d=self.date,
            t=self.theme, g=self.grade)


class Tasks(object):
    def __init__(self):
        self.tasks = set()

    def add_task(self, task):
        self.tasks.add(task)

    def __iter__(self):
        for task in self.tasks:
            yield task

Code: Alles auswählen

>>> import todo
>>> tasks = todo.Tasks()
>>> tasks.add_task(todo.Task('Mathe', '28.06.2014', 'Bruchrechnen', 'befriedigend'))
>>> tasks.add_task(todo.Task('Deutsch', '27.06.2014', 'Rechdschraibuhnk', 'ungenuegend'))
>>> for task in tasks:
...     print task
... 
Task: Mathe 28.06.2014 Bruchrechnen befriedigend
Task: Deutsch 27.06.2014 Rechdschraibuhnk ungenuegend
Das soll jetzt nur mal den Einsatz von Klassen demonstrieren und muss jetzt nicht zwingend für das, was Du vorhast 1:1 passen...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Ok, dann werde ich das demnächst mit Klassen probieren. Danke.
Xfd7887a
User
Beiträge: 135
Registriert: Montag 23. Juni 2014, 17:11

Ich glaube, ich werde mich erstmal gründlicher in die OOP einarbeiten. Das ist doch komplizierter als ich dachte und ich weil mein Programm nicht "verschlimmbessern".
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@mutetella: Das was du "theme" nennst, würde man AFAIK eher als "topic" bezeichnen. Wobei laut Online-Wörterbuch "theme" genau so gut passen würde. Für mich klingt es in dem Zusammenhang jedenfalls besser, "topic" zu sagen.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Xfd7887a hat geschrieben:Ich glaube, ich werde mich erstmal gründlicher in die OOP einarbeiten. Das ist doch komplizierter als ich dachte und ich weil mein Programm nicht "verschlimmbessern".
OOP selbst ist relativ leicht zu verstehen. Insbesondere dann, wenn man Vererbung erstmal außen vorlässt. Es wird eigentlich erst dann wirklich komplex, wenn man die besagte Vererbung nutzt und wenn man die Funktionalität auf Basis bestimmter Protokolle aufbaut. Im hier gezeigten Beispiel wurde das Protokoll für Iteratoren mittels ``__iter__`` implementiert. Häufig findet man auch Implementationen von ``__str__`` oder ``__repr__``. Das sieht anfangs wie Voodoo aus (ist es ja eigentlich auch ^^), aber mit der Zeit gewöhnt man sich daran und beginnt, die entsprechenden Vorteile zu erkennen und sinnvoll zu nutzen. Ob man die Klasse ``Tasks`` in seiner vorgeschlagenen Form wirklich so benötigt oder ob man nicht direkt ein Set (also ohne die "Hülle") benutzen möchte, sei übrigens mal dahingestellt...
Antworten