Seite 1 von 2
Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 06:08
von mutetella
Gibt es eine Möglichkeit, eine exception und das Ergebnis eines Vergleichs gemeinsam zu behandeln:
Code: Alles auswählen
try:
int(value)
except ValueError or value <= 0:
raise ValueError('error')
So geht's nicht, weil `except` keinen Vergleich abfängt, klar. Aber welche Möglichkeit gäbe es? Oder muss das zwingend in zwei Schritten gemacht werden?
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 07:09
von DasIch
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 14:50
von snafu
mutetella hat geschrieben:Gibt es eine Möglichkeit, eine exception und das Ergebnis eines Vergleichs gemeinsam zu behandeln:
Code: Alles auswählen
try:
int(value)
except ValueError or value <= 0:
raise ValueError('error')
Ja, indem man das Fehlerhandling sinnvoll ergänzt und so Muster wie ``except SpamError: raise SpamError`` vermeidet. Mein Vorposter hat das bereits mit Code veranschaulicht. Denn letztlich geht es um die Art der Exception und nicht darum, ob jetzt der von dir erstellte Code den `ValueError` geworfen hat oder ob es fremder Code war.
Übrigens: Wenn ich Situationen habe, wo ich einen bestimmten Fehlertyp anfange und nur werfen möchte, wenn bestimmte zusätzliche Bedingungen zutreffen (hat man z.B. oft bei `OSError`), dann nehme ich meistens ein nacktes `raise`, damit der Original-Fehler geworfen wird.
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 16:40
von mutetella
Entweder verstehe ich eure Antworten oder ihr meine Frage nicht...
Ich möchte einen Wert auf drei Bedingungen hin überprüfen:
- Lässt er sich in eine Ganzzahl umwandeln und
- ist diese Zahl nicht kleiner oder
- gleich 0.
Trifft eine der Bedingungen zu, soll eine für alle Fälle gleiche Exception geworfen werden. Also:
Code: Alles auswählen
try:
value = int(value)
except ValueError:
raise ValueError('Value must be a number greater zero!')
if value <= 0:
raise ValueError('Value must be a number greater zero!')
Meine Frage ist eben, ob die Prüfung außerhalb des `try` Blocks sein muss oder sich elegant integrieren ließe?
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 17:04
von Sirius3
@mutetella: man kann die Exception nur einmal behandeln, wenn man innerhalb des try-Blocks eine Exception bei falschem value zu werfen:
Code: Alles auswählen
try:
value = int(value)
if value <= 0:
raise ValueError()
except ValueError:
raise ValueError('Value must be a number greater zero!')
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 17:18
von BlackJack
@mutetella: Was gefällt Dir an der Antwort von DasIch nicht? Wenn die Umwandlung nicht funktioniert löst die einen `ValueError` aus, und wenn der Wert <= 0 ist, löst die einen `ValueError` aus. Also das was Du willst. Bei Deiner Lösung ersetzt Du die Meldung vom `ValueError` falls die Umwandlung fehlschlägt durch eine schlechtere Meldung mit weniger Informationen. Einfach sein lassen.

Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 17:50
von mutetella
BlackJack hat geschrieben:Was gefällt Dir an der Antwort von DasIch nicht?
Dass ich für den Fall einer nicht möglichen Umwandlung keine bezugnehmende Meldung ausgeben kann.
BlackJack hat geschrieben:Bei Deiner Lösung ersetzt Du die Meldung vom `ValueError` falls die Umwandlung fehlschlägt ...
Gerade das möchte ich ja. Eine Meldung ausgeben, die Bezug auf das jeweilige Argument nimmt und dem Nutzer erklärt, welcher Wert vom Programm an der Stelle erwartet wird.
@Sirius3
Sowas hab' ich gesucht, danke! War mal wieder viel zu naheliegend für mich, um d'raufzukommen...

Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 17:50
von DasIch
BlackJack hat geschrieben:Bei Deiner Lösung ersetzt Du die Meldung vom `ValueError` falls die Umwandlung fehlschlägt durch eine schlechtere Meldung mit weniger Informationen. Einfach sein lassen.

Ich find die Meldung nicht toll weil sie das problematisch Objekt nicht beinhaltet aber ich würde mich nicht allein auf Python verlassen.
Als User finde ich es besser wenn Libraries einen eigene Exception Typen und vielsagende Meldungen haben, am besten noch über Text hinaus Attribute mit denen man was brauchbares anfangen kann. Ich hab keine Lust zu raten ob ein ValueError jetzt so auftauchen sollte oder ob es ein Bug ist oder was auch immer.
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 19:18
von bwbg
Bau Dir doch eine Fehler-Monade

Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 19:51
von mutetella
Ui, da hab' ich ja wieder ein Fass aufgemacht...

Wie gesagt, ich möchte dem Nutzer fehlerhafte Eingaben erklären und auf mögliche Werte hinweisen:
Code: Alles auswählen
MISSING_ARGUMENT = 'Required argument \'{}\' not found.'
WRONG_TYPE_OR_VALUE = ('Argument \'{}\' must be of type \'{}\''
'with these value: {}')
class Recurrence(object):
FREQUENCIES = {'d': Daily, 'w': Weekly}
def __init__(self, frequency=None, interval=None):
if frequency is None:
raise TypeError(
MISSING_ARGUMENT.format('frequency')
)
else:
try:
self.frequency = self.FREQUENCIES[frequency[0]]
except (TypeError, KeyError):
raise TypeError(
WRONG_TYPE_OR_VALUE.format(
'frequency', 'str',
'\'d\', \'w\', \'m\' or \'y\''
)
)
try:
if interval <= 0:
raise ValueError()
self.interval = int(interval)
except ValueError:
raise TypeError(
WRONG_TYPE_OR_VALUE.format(
'interval', 'int',
'Positiv or negativ number but not zero'
)
)
DasIch hat geschrieben:... aber ich würde mich nicht allein auf Python verlassen. [...] ... am besten noch über Text hinaus Attribute mit denen man was brauchbares anfangen kann.
Was meinst Du damit? Und welchen Vorteil haben "... eigene Exception Typen ..."?
Um ehrlich zu sein bin ich etwas ratlos, wie und wo ich fehlerhafte Eingaben behandeln soll:
- In den Klassen/Funktionen, in denen sie ausgelöst werden?
- Bereits beim Parsen der Argumente?
- Innerhalb eines eigenen Bereichs, in den Fehler aus den einzelnen Modulen gesendet werden?
Es handelt sich hier nicht um ein Modul sondern eine CLI Anwendung.
@bwbg
pillmuncher hat hier im Forum schon mal eine IMHO gute Erklärung zu monads geschrieben, ich versuch' noch immer, das zu verstehen...
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Dienstag 23. Februar 2016, 20:01
von Sirius3
@mutetella: es gibt in Python für Strings ", ', """ und ''' so dass es eigentlich nie nötig ist, Anführungszeichen zu escapen. Das macht Strings nur unleserlich.
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 06:42
von DasIch
mutetella hat geschrieben:Ui, da hab' ich ja wieder ein Fass aufgemacht...

Wie gesagt, ich möchte dem Nutzer fehlerhafte Eingaben erklären und auf mögliche Werte hinweisen:
Code: Alles auswählen
MISSING_ARGUMENT = 'Required argument \'{}\' not found.'
WRONG_TYPE_OR_VALUE = ('Argument \'{}\' must be of type \'{}\''
'with these value: {}')
class Recurrence(object):
FREQUENCIES = {'d': Daily, 'w': Weekly}
def __init__(self, frequency=None, interval=None):
if frequency is None:
raise TypeError(
MISSING_ARGUMENT.format('frequency')
)
else:
try:
self.frequency = self.FREQUENCIES[frequency[0]]
except (TypeError, KeyError):
raise TypeError(
WRONG_TYPE_OR_VALUE.format(
'frequency', 'str',
'\'d\', \'w\', \'m\' or \'y\''
)
)
try:
if interval <= 0:
raise ValueError()
self.interval = int(interval)
except ValueError:
raise TypeError(
WRONG_TYPE_OR_VALUE.format(
'interval', 'int',
'Positiv or negativ number but not zero'
)
)
Mach frequency in der Funktionssignatur nicht optional, wenn es dies tatsächlich nicht ist.
Wenn du Exceptions wirfst die ein bestimmtes Objekt betreffen, dann pack das Objekt in die Fehlermeldung: "frequency should be 'd', 'w', 'm' or 'y' but is: {!r}".format(frequency). Ich möchte nicht nur wissen was schief gegangen ist und was hätte passieren sollen, sondern auch wieso der Fehler aufgetreten ist. Wie soll ich auch den Fehler beheben ohne zu wissen wieso er aufgetreten ist? Je nachdem wie tief in fremdem Code der Fehler auftaucht ist dies ohne Debugger sonst nicht herauszufinden.
DasIch hat geschrieben:... aber ich würde mich nicht allein auf Python verlassen. [...] ... am besten noch über Text hinaus Attribute mit denen man was brauchbares anfangen kann.
Was meinst Du damit? Und welchen Vorteil haben "... eigene Exception Typen ..."?
Konkret für den von dir gezeigten Code haben die keine Vorteile. Grundsätzlich haben sie den Vorteil dass du Probleme genauer beschreiben kannst.
Um ehrlich zu sein bin ich etwas ratlos, wie und wo ich fehlerhafte Eingaben behandeln soll:
- In den Klassen/Funktionen, in denen sie ausgelöst werden?
- Bereits beim Parsen der Argumente?
- Innerhalb eines eigenen Bereichs, in den Fehler aus den einzelnen Modulen gesendet werden?
Wechsel die Perspektive. Exceptions sind Teil deiner API und wenn sie auftreten möchte der Nutzer der API damit sinnvoll umgehen können. In diesem Kontext tauchen dann Fragen auf wie "Was ist schief gegangen?", "Wieso ist es schief gegangen?" oder "Wie behebe ich den Fehler?". Soweit es geht solltest du schauen dass sich diese Fragen durch die Exception beantworten lassen.
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 08:46
von snafu
mutetella hat geschrieben:Um ehrlich zu sein bin ich etwas ratlos, wie und wo ich fehlerhafte Eingaben behandeln soll:
- In den Klassen/Funktionen, in denen sie ausgelöst werden?
- Bereits beim Parsen der Argumente?
- Innerhalb eines eigenen Bereichs, in den Fehler aus den einzelnen Modulen gesendet werden?
Das kommt auf die Art des Fehlers an: Beim Parsen der Argumente kann es sich um den falschen Typen handeln, wenn z.B. ein Argument nicht als Zahl erkannt werden kann (`TypeError`). Innerhalb von Klassen oder Funktionen kann der Wertebereich des Arguments falsch sein (`ValueError)`, z.B. weil eine nicht-negative Zahl erwartet wird.
Einen eigenen Bereich für die Fehlerausgabe würde ich bloß für den Teil gestalten, den der Benutzer der CLI sieht. Dann kann man dann die Meldung, mit der eine Exception geworfen wurde, auf dem Bildschirm anzeigen. In der einfachsten Form etwa so:
Code: Alles auswählen
def main():
try:
args = parse_args()
main_loop(args)
except Exception as exc:
msg = 'ERROR: {}'.format(exc)
sys.exit(msg)
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 14:23
von mutetella
DasIch hat geschrieben:Mach frequency in der Funktionssignatur nicht optional, wenn es dies tatsächlich nicht ist.
Macht das die Behandlung des "Fehlers", `frequency` nicht definiert zu haben, nicht umständlicher?
DasIch hat geschrieben:... aber ich würde mich nicht allein auf Python verlassen.
Was meinst Du damit?
snafu hat geschrieben:Das kommt auf die Art des Fehlers an:
Letztlich provoziert ein fehlerhaftes Argument ja an anderer Stelle einen Fehler. Der Parser müsste also Informationen haben, die ihn selbst gar nicht betreffen, um z. B. den von einer Klasse erwarteten Typ im Vorfeld zu prüfen. In welchen Fällen macht man sowas?
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 14:38
von BlackJack
@mutetella: Wenn Du `frequency` nicht übergibst und es keinen Defaultwert hat, dann löst Python an der Stelle doch schon einen `TypeError` aus.
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 14:50
von mutetella
@BlackJack
Ja schon, aber den kann ich ja dann nicht innerhalb ``__init__()`` abfangen und mit einer eigenen Meldung versehen... Beantwortet das vielleicht schon meine Frage an snafu, will heißen, dass das z. B. ein Fehler wäre, den der Parser behandelt?
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 15:21
von BlackJack
@mutetella: Warum willst Du das denn mit einer eigenen Meldung versehen? Wenn Du das grundsätzlich haben möchtest, dann müsstest Du diesen Code ja in *jeder* Funktion und Methode schreiben. Das erscheint mir ein bisschen, äh, ehrgeizig. Kann sein das die Standardmeldung etwas präziser sein könnte (also zumindest soweit es so eine Funktionssignatur mit Namen gibt, das ist bei in C implementierten Funktionen ja nicht zwingend der Fall), aber meinst Du nicht die Meldung das zu wenig Argumente übergeben wurden, reicht dem Programmierer nicht aus? Oder versuchst Du hier mit Ausnahmen Fehler die der *Benutzer* gemacht hat für den Benutzer zu ”beantworten”? Dafür sind Ausnahmen nicht gedacht.
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 16:08
von mutetella
BlackJack hat geschrieben:[...] reicht dem Programmierer nicht aus?
Doch klar, Programmierer sollten sich weiterhelfen können...
BlackJack hat geschrieben:[...] für den Benutzer zu ”beantworten”?
Ja genau! Ich möchte meine Anwendung mit Fehlermeldungen versehen, die dem Benutzer so weit als möglich Hilfestellung geben.
BlackJack hat geschrieben:Dafür sind Ausnahmen nicht gedacht.

Ja aber was/wie denn dann?
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 16:16
von BlackJack
@mutetella: Wenn diese Klasse mit einem Argument zu wenig aufgerufen wurde, dann hat doch der Programmierer etwas falsch gemacht und nicht der Benutzer. Ich verstehe die Frage darum nicht so ganz‽
Re: Vergleich und Fehlerabfang in einem möglich?
Verfasst: Mittwoch 24. Februar 2016, 16:17
von snafu
@mutetella
Was das Parsen von Kommandozeilenargumenten angeht, so empfehle ich einen Blick in die `argparse`-Dokumentation. Da kann man frühzeitig die Argumente in die erwarteten Datentypen konvertieren lassen und die Fehlerausgabe im Falle von nicht konvertierbaren Argumenten durch die `argparse`-Bibliothek erledigen lassen.
Und die so erhaltenen Datentypen würde ich an die internen Klassen und Funktionen deines Programms weiterleiten. Da kann man dann bei Bedarf noch Werteprüfungen vornehmen (z.B. nicht-negativ) sowie andere Plausibilitätsprüfungen durchführen und mit Exceptions reagieren.
mutetella hat geschrieben:Der Parser müsste also Informationen haben, die ihn selbst gar nicht betreffen, um z. B. den von einer Klasse erwarteten Typ im Vorfeld zu prüfen.
Und wo ist das Problem? Der Parser weiß so oder so nicht, was anschließend mit dem von ihm gelieferten Ergebnis passiert. Wozu sollte er das auch wissen müssen?
Du als Programmierer sollst dem Parser doch sagen, welche Argumente erwartet werden, von welchem Typ sie sein sollen, sowie ggf ungültige Kombinationen von Argumenten definieren. Der Parser verrichtet als abgeschlossene Einheit dann die Interpretation der Eingabe und gibt dir im Falle eines fehlerfreien Durchlaufs eine Struktur von Argumenten zurück, die an andere Programmteile zur weiteren Verarbeitung übergeben werden können.