FileDB
@deadshox: Wenn Du hinter den Logging-Aufruf nicht noch ein ``raise`` setzt, dann kannst Du Dir das ``except`` vielleicht wirklich sparen. Die Frage ist doch an jeder Stelle, ob Du die Ausnahme überhaupt ”verschlucken” solltest. In dem Beispiel hat irgendetwas beim Laden/Parsen der Datei nicht funtkioniert. Das Programm würde aber weitermachen, als wäre nichts passiert. Sollte es das tun? Denn danach wird ja sicher mit den Daten irgendetwas gemacht. Also mit den Daten die nicht geladen werden konnten — also wird es dort entweder wieder eine Ausnahme geben, oder ein falsches Ergebnis.
`Exception` fängt noch immer alle Fehler ab, du muss schon prüfen, welche Fehler genau auftreten können. Dazu hilft ein Blick in die Dokumentation zu `open`. Die mögliche Exception ist `IOError`, also behandelst du genau diese:deadshox hat geschrieben:Also dann eher so etwas wie:Wenn nicht, kannst du etwas genauer werden? Wenn es oberes nicht ist, kann ich mir ja das try:except gleich sparen.Code: Alles auswählen
try: with open(self._bin, 'rb') as handle int("spam") self._data = pickle.load(handle) except Exeption, e: logging.error('Error: ' % e)
Code: Alles auswählen
try:
with open(self._bin, 'rb') as handle
int("spam")
self._data = pickle.load(handle)
except IOError:
logging.error("Could not open file: %s" % self._bin)
Das Leben ist wie ein Tennisball.
@blackjack, in der _load Methode macht es mMn Sinn, da, wenn die Datei nicht existiert, sie angelegt wird. Da muss ja nichts abgebrochen werden.
@EyDu, wäre Variante 1 nicht einfacher, da man die Fehlermeldung dort einfach nur zum Loggen durch reicht? Denn eine direkte Ausgabe wäre für mich persönlich nicht nötig. Evtl könnte man noch ein 'print' setzen für die Konsole. Jeden möglichen Fehler abfangen würde ich irgendwie als zu aufwendig empfinden.
@EyDu, wäre Variante 1 nicht einfacher, da man die Fehlermeldung dort einfach nur zum Loggen durch reicht? Denn eine direkte Ausgabe wäre für mich persönlich nicht nötig. Evtl könnte man noch ein 'print' setzen für die Konsole. Jeden möglichen Fehler abfangen würde ich irgendwie als zu aufwendig empfinden.
Einfacher vielleicht, aber unter umständen auch vollkommen falsch. Angenommen, du möchtest zwei Werte (in diesem etwas seltsamen Szenario) vertauschen. Leider verschreibst du dich ein wenig:
Ganz offensichtlich sind `ah` und `beh` nicht vorhanden, da du alle Fehler behandelst, wird dir dies aber nicht auffallen. Das Programm läuft gemütlilch weiter, obwohl hier ein ganz offensichtlicher Fehler vorhanden ist. Vielleicht irgendwann später im Verlauf des Programms gibt es einen Folgefehler, was eine Fehlersuche unglaublich anstregend machen kann. Da ist es natürlich schön, wenn du den Fehler geloggt hast, dir wird das Problem aber unter Umständen gar nicht erst aufflallen (je nach Umfang des Logs). Du verwirfst damit also nicht nur Fehler von außen, sondern möglicherweise auch Programmierfehler.
Code: Alles auswählen
>>> a, b = 42, 23
>>> try:
... a, b = beh, ah
... except:
... pass
...
>>> a, b
(42, 23)
Das Leben ist wie ein Tennisball.
Ich hoffe ich verstehe dich nicht falsch aber ein:
Sagt mir doch an, was falsch gemacht wurde.
Es ist ja im Endeffekt nichts anderes als:
Nur das es mehr oder weniger abgefangen wurde.
Vielleicht hätte ich noch dazu schreiben sollen das es mehr mein Ziel ist, ein reibungslosen Programmablauf zu erreichen, als eine eine Programm zu haben was mit Fehlermeldungen um sich wirft, wenn es welche gibt.
Code: Alles auswählen
>>> a, b = 42, 23
>>> try:
... a, b = beh, ah
... except Exception, e:
... print e
...
name 'beh' is not defined
Es ist ja im Endeffekt nichts anderes als:
Code: Alles auswählen
>>> a, b = 42, 23
>>> a, b = beh, ah
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'beh' is not defined
Vielleicht hätte ich noch dazu schreiben sollen das es mehr mein Ziel ist, ein reibungslosen Programmablauf zu erreichen, als eine eine Programm zu haben was mit Fehlermeldungen um sich wirft, wenn es welche gibt.
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:deadshox hat geschrieben:Nur das es mehr oder weniger abgefangen wurde.
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
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.
In der Hoffnung dich nun verstanden zu haben, habe einmal die _load() Methode ausgebaut.
Durch diese Variante konnte ich auch die Methode 'check()' löschen, da sie nun überflüssig ist.
Bin ich auf dem richtigen Weg?
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)
Bin ich auf dem richtigen Weg?
@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`.
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`.
Ok. Das würde dann also wie folgt aussehen.
Der 'import' sitzt jetzt nur zum zeigen da und wird sonst im Kopf des Modules stehen.
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 = {}
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.
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.
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.
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.