FileDB

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

deadshox hat geschrieben:Nur das es mehr oder weniger abgefangen wurde.
Merkst du nicht das Problem bei "mehr oder weniger"? Du weisst nämlich nicht, weche Exceptions du möglicherweise noch alles abfängst. Nur weil du sie bemerkst heißt es nicht, dass es eine ordentliche Behandlung ist. Den Fehler in ein Log zu schreiben ist nur dann eine vernünftige Lösung wenn man garantieren kann, dass der Zustands des Programms danach *immer* gültig ist. Dadurch, dass du einfach alle Fehler wegwirfst baust du unter Umständen ganz neue ein. Ich versuche es noch einmal mit einem komplexeren Beispiel:

Code: Alles auswählen

>>> def bubblesort(data):
...     n = len(data)
...     while True:
...         switched = False
...         for i in range(n-1):
...             if data[i] > data[i+1]:
...                 try:
...                     data[i], data[i+1] = dataasdf[i+1], dataasd[i]
...                     switched = True
...                 except Exception, e:
...                     pass
...         n = n - 1
...         if not (n and switched):
...             break
... 
>>> def stupid_min(data):
...     data = data[:]
...     bubblesort(data)
...     return data[0]
... 
>>> import random
>>> data = range(10)
>>> random.shuffle(data)
>>> data
[9, 8, 1, 3, 2, 4, 6, 0, 7, 5]
>>> stupid_min(data)
9
Ganz offensichtlich gibt es oben wieder zwei `NameErrors` und es werden alle Exceptions abgefangen (oder in ein Log geschrieben, was hier kein Unterschied macht). `stupid_min` verwendet nun Bubblesort um das Minimum zu bestimmen. Da beim Sortieren kein Fehler geworfen wird, macht `stupid_min` einfach mit den falschen Daten weiter. Ganz offensichtlich ist das Programm zu diesem Zeitpunkt in keinem gültigen Zustand mehr. Statt dem Minimum könnte hier natürlich alles mögliche schief gehen, wie das ungewollte Überschreiben von Dateien, unbeabsichtigen Operationen in der Datenbank und was man sich noch alles Vorstellen kann.

Durch wildes Abfangen aller Fehler machst du dein Programm im Allgemeinen nicht fehlertoleranter, sondern baust noch mehr ein. Wenn es irgendwo im Programm unterwartet zu Problemen kommt, dann muss es krachen, da du über den Zustand des Programms keine Aussage mehr treffen kannst. Es funkioniert dann ggf. nur noch weil du Glück hattest und das ist ganz sicher kein Verhalten welches du dir wünscht.
Das Leben ist wie ein Tennisball.
Benutzeravatar
lynadge
User
Beiträge: 112
Registriert: Sonntag 4. April 2010, 10:17

In der Hoffnung dich nun verstanden zu haben, habe einmal die _load() Methode ausgebaut. :)

Code: Alles auswählen

def _load(self):
    """Load data from file."""

    try:
        with open(self._bin, 'rb') as handle
            self.data = pickle.load(handle)
    except IOError as e:
        if e.errno == 2:
            logging.warning('Try to create file, given was not found. %s'\
                            % self._bin)
            open(self._bin, 'w').close()
        elif e.errno == 13:
            logging.error('Permission denied. %s' % self._bin)
Durch diese Variante konnte ich auch die Methode 'check()' löschen, da sie nun überflüssig ist.

Bin ich auf dem richtigen Weg? ;)
BlackJack

@deadshox: Vorausgesetzt, dass es in Ordnung ist, wenn die Daten nicht geladen werden ohne dass der Aufrufer das mitbekommt und `self.data` auch nach dem Aufruf noch an die alten Daten gebunden ist, könnte man das so machen.

Die Zahlen für die Fehlernummer würde ich durch Konstanten aus `errno` ersetzen. Dann ist der Quelltext (etwas) verständlicher und vor allem auch plattformunabhängiger. In diesem Falle also `errno.ENOENT` und `errno.EACCESS`.
Benutzeravatar
lynadge
User
Beiträge: 112
Registriert: Sonntag 4. April 2010, 10:17

Ok. Das würde dann also wie folgt aussehen.

Code: Alles auswählen

import errno

def _load(self):
    """Load data from file."""

    try:
        with open(self._bin, 'rb') as handle
            self.data = pickle.load(handle)
    except IOError as e:
        if e.errno == errno.ENOENT:
            logging.warning('Try to create file, given was not found. {0}'\
                            .formatself._bin))
            open(self._bin, 'w').close()
        elif e.errno == errno.EACCES:
            logging.error('Permission denied to given file. {0}'\
                          .format(self._bin))

        self.data = {}
Der 'import' sitzt jetzt nur zum zeigen da und wird sonst im Kopf des Modules stehen.
Benutzeravatar
lynadge
User
Beiträge: 112
Registriert: Sonntag 4. April 2010, 10:17

Ich habe mal eine überarbeitete Version hoch geladen.

https://github.com/deadshox/FileDB/tree/0.4

Ich hoffe ich konnte nun alle von euch genannten Punkte mit einbauen und bin auf dem Weg das diese kleine Lib halbwegs brauchbar ist. :)
Benutzeravatar
lynadge
User
Beiträge: 112
Registriert: Sonntag 4. April 2010, 10:17

Neue Version 0.5.

https://github.com/deadshox/FileDB/tree/0.5

Dort gibt es nun eine reload() Methode, diese schaut anhand einer Checksumme ob die Daten neu geladen werden müssen oder nicht. Für diese Methode dazugekommen ist auch die get_checksum() Methode.

Um sich dann noch eine ID erstellen zu können, habe ich noch create_id() hinzugefügt, diese Methode erstellt aus einem Integer einen Hex wert, den man dann als ID nutzen kann. Z.b. könnte der Integer ein Timestamp sein.

:)
Antworten