Seite 3 von 4

Re: Aufgabenverwaltung

Verfasst: Samstag 28. Juni 2014, 13:31
von Sirius3
Btw.: für pickle solltest Du die Dateien für binäres Lesen und Schreiben öffnen.

Re: Aufgabenverwaltung

Verfasst: Samstag 28. Juni 2014, 13:33
von Xfd7887a

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.

Re: Aufgabenverwaltung

Verfasst: Samstag 28. Juni 2014, 13:43
von 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.

Re: Aufgabenverwaltung

Verfasst: Samstag 28. Juni 2014, 13:53
von mutetella
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

Re: Aufgabenverwaltung

Verfasst: Samstag 28. Juni 2014, 13:56
von Xfd7887a
Ok, das habe ich verstanden. Also ist json im Allgemeinen die bessere Wahl.

Re: Aufgabenverwaltung

Verfasst: Samstag 28. Juni 2014, 14:19
von mutetella
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

Re: Aufgabenverwaltung

Verfasst: Samstag 28. Juni 2014, 14:23
von Xfd7887a
Ok, dann werde ich das demnächst mit Klassen probieren. Danke.

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 11:46
von Xfd7887a
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".

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 11:52
von snafu
@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.

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 12:05
von snafu
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...

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 12:09
von mutetella
@snafu
Geb' ich Dir Recht, `topic` finde ich auch besser... Wobei ich mir nicht sicher bin, ob ich eine `task`-Klasse überhaupt in dem Maße spezialisieren würde, muss aber auch zugeben, dass ich noch nicht wirklich verstehe, wohin Xfd7887a überhaupt möchte...

mutetella

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 12:14
von mutetella
@snafu
Ich würde wahrscheinlich eine `Tasks` Klasse verwenden, weil ich zusammengehörende Dinge gerne in einer Klasse zusammenfasse, also z. B. `Tasks.load()`, `Tasks.filter()` etc. Natürlich ließe sich das auch auf Modulebene über ein Set oder so organisieren...

mutetella

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 12:23
von BlackJack
Mal ums Speichern und Laden erweitert und vollkommen ungetestet:

Code: Alles auswählen

import json
from datetime import datetime as DateTime

DATE_FORMAT = '%Y-%m-%d'


class Task(object):
    def __init__(self, subject, date, topic, grade):
        self.subject = subject
        self.date = date
        self.topic = topic
        self.grade = grade
 
    def __cmp__(self, other):
        return cmp(self.subject, other.subject)

    def __hash__(self):
        return hash(self.subject)

    def __str__(self):
        return 'Task: {0.subject} {0.date} {0.topic} {0.grade}'.format(self)

    def to_list(self):
        return [
            self.subject,
            self.date.strftime(DATE_FORMAT),
            self.topic,
            self.grade,
        ]

    @classmethod
    def from_list(cls, values):
        subject, date, topic, grade = values
        return cls(subject, DateTime.strptime(date, DATE_FORMAT), topic, grade)
 
 
class Tasks(object):
    def __init__(self, tasks=()):
        self.tasks = set()
        self.add_tasks(tasks)
 
    def add_task(self, task):
        self.tasks.add(task)
 
    def add_tasks(self, tasks):
        for task in tasks:
            self.add_task(task)

    def __iter__(self):
        return iter(self.tasks)

    def to_dict(self):
        return {'tasks': [task.to_list() for task in self]}

    def save(self, filename):
        with open(filename, 'w') as json_file:
            json.dump(json_file, self.to_dict())

    @classmethod
    def from_dict(cls, values):
        return cls(Task.from_list(t) for t in values['tasks'])

    @classmethod
    def load(cls, filename):
        with open(filename, 'r') as json_file:
            return cls.from_dict(json.load(json_file))
Hier fängt dann eine `Tasks`-Klasse IMHO an Sinn zu machen.

`Task.__str__()` und `Tasks.__iter__()` sind überarbeitet und zumindest die `__iter__()` finde ich so besser als eine Schleife mit ``yield`` zu schreiben.

Die JSON-Struktur habe ich auf oberster Ebene geringfügig geändert, und ich würde wohl auch die einzelnen Einträge lieber als Wörterbücher mit Schlüsseln statt als Liste mit ”anonymen” Elementen speichern. Das würde die Daten zwar aufblähen, aber ist immer noch besser als XML. :-)

Edit: Ach so, und ich habe bei `Task` die Methoden `__cmp__()` und `__hash__()` implementiert, damit das `set()` bei `Tasks` mehr Sinn macht und es sich so verhält wie die ursprüngliche Lösung, dass es immer nur einen Eintrag pro Fach geben kann/darf.

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 13:31
von Xfd7887a
Wie schon gesagt, ich werde mich erstmal versuchen reinzufitzen. Das gezeigte wirkt schon ziemlich kompliziert. Wahrscheinlich gewöhnt man sich wirklich dran, ich fand früher Funktionen auch kompliziert und habe nicht verstanden, warum man die nutzt.

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 14:03
von mutetella
@Xfd7887a
Ohne Dich jetzt mit einer weiteren Neuheit komplett überfordern zu wollen: Wenn ich fremden (oder oft auch meinen eigenen :mrgreen: ) Code nicht verstehe, hilft mir das `pdb` Modul ungemein. Erstmal (und in der Regel) lässt sich das durch Einfügen von ``import pdb; pdb.set_trace()`` sehr einfach nutzen. Hier mal ein kleines Beispiel:

Code: Alles auswählen

def debug_example(first=None, second=None):
    import pdb; pdb.set_trace()
    third = first + second
    import pdb; pdb.set_trace()
    return third
Wenn Du eine so präparierte Funktion aufrufst, stoppt die Ausführung an jedem ``pdb.set_trace()`` Aufruf und Du landest am pdb-eigenen Prompt, an dem Du, ähnlich der Pythonshell, auf Namen, Funktionen etc. zugreifen kannst. Mit 'c' fährst Du in der Ausführung fort, mit 'q' beendest Du `pdb` und die Ausführung. In diesem Beispiel könnte ein Aufruf von `debug_example()` so aussehen:

Code: Alles auswählen

>>> debug_example('eins', 'zwei')
> <stdin>(3)debug_example()
(Pdb) first
'eins'
(Pdb) second
'zwei'
(Pdb) third
*** NameError: name 'third' is not defined
(Pdb) c
> <stdin>(5)debug_example()
(Pdb) third
'einszwei'
(Pdb) q
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in debug_example
  File "<stdin>", line 5, in debug_example
  File "/usr/lib/python2.7/bdb.py", line 49, in trace_dispatch
    return self.dispatch_line(frame)
  File "/usr/lib/python2.7/bdb.py", line 68, in dispatch_line
    if self.quitting: raise BdbQuit
bdb.BdbQuit
Wenn Du also mit BlackJack's Beispiel herumspielst, kannst Du mit `pdb` die Ausführung an einem Punkt, der Dir unklar ist, unterbrechen und quasi die Umgebung in Ruhe betrachten bevor Du fortfährst.

Einmal `pdb` verwendet möchte man das nie mehr missen... :wink: Noch als Anmerkung: Die Zeile ``import pdb; pdb.set_trace()`` entspricht eigentlich nicht der gängigen Python Konvention, wird aber in der Praxis so verwendet, weil es einfach zweckmäßig ist. Und damit wurde diese "Unkonvention" zur Konvention und alles ist gut... :mrgreen:

mutetella

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 17:53
von Xfd7887a
Danke für den Tipp mutella :D
Ich denke mal, ich werde mir sowas http://www.python-forum.de/viewtopic.php?f=6&t=30149 bauen, aber eben erstmal in der Konsole. Das Projekt scheint sich gut für OOP-Anwendung zu eignen.

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 18:37
von mutetella
@Xfd7887a
Also nicht, dass ein Konsolen-Tamagotchi ungeeignet wäre... Aber weshalb bleibst Du nicht bei Deiner bereits begonnenen Aufgabenverwaltung?

mutetella

Re: Aufgabenverwaltung

Verfasst: Sonntag 29. Juni 2014, 20:17
von Xfd7887a
Das wollte ich danach machen. Es schien mir, dass ich OOP viel besser an sowas nachvollziehen kann. Außerdem wollte ich mal wieder was neues machen :D

Re: Aufgabenverwaltung

Verfasst: Montag 30. Juni 2014, 18:38
von Xfd7887a
Ich habe mir jetzt BlackJacks Code näher angeschaut und habe ein paar Fragen:

Code: Alles auswählen

    def __cmp__(self, other):
        return cmp(self.subject, other.subject)
[*]Was macht diese Funktion? Wie kann man zwei Fächer vergleichen?

Code: Alles auswählen

    def __hash__(self):
        return hash(self.subject)
[*]Gleiche Frage. In der Doku steht ja:
Return the hash value of the object (if it has one). Hash values are integers. They are used to quickly compare dictionary keys during a dictionary lookup.
Aber wie kann ich mir das jetzt vorstellen?
[*]Was sind @classmethods, in meinem Buch steht nur was von staticmethods?
[*]Was ist cls? Scheint was mit den classmethods zu tun zu haben.

Sorry für die vermutlich dummen Fragen :D, aber ich tu mich gerade schwer, dass alles zu verstehen.

Re: Aufgabenverwaltung

Verfasst: Montag 30. Juni 2014, 19:19
von EyDu