Seite 2 von 2

Re: Kommandos inkommensurabel

Verfasst: Freitag 28. Mai 2021, 13:33
von kbr
@hcshm: Ich würde für die möglicherweise fehlerträchtige Datumsumwandlung einen separaten Konverter bevorzugen, der als eigenständige Funktion implementiert ist und dadurch auch für andere Stellen im Programm wiederverwendbar bleibt.

Code: Alles auswählen

def convert_to_date(some_input):
    ...
    return date

Zudem ist so eine Funktion auch separat testbar.

Bei der Ausführung dieser Funktion kannst Du dann bestimmen, was im Fehlerfall passiert und wie darauf ggf. reagiert werden soll (ignorieren, loggen, oder was auch immer).

Übergibt man die korrekt konvertierten Daten nun an die neu angelegte Instanz, so bleibt der Code sehr aufgeräumt und man arbeitet immer mit definierten einheitlichen Datentypen:

Code: Alles auswählen

class Person:
    def __init__(self, name, geburtstag):
        self.name = name
        self.geburtstag = geburtstag

Das ist idealerweise schon alles.

Auch könnte man die Daten bereits beim Import in das korrekte Format überführen, wozu ein Konverter ebenfalls von Vorteil ist. Denn z.B. numpy oder auch pandas bieten entsprechende hooks für genau diesen Anwendungsfall.

Re: Kommandos inkommensurabel

Verfasst: Freitag 28. Mai 2021, 13:49
von Sirius3
Du hast wirklich eine lustige Definition von Robustheit. Robust ist bei mir nicht, dass das Programm rät, was denn der Nutzer gemeint haben könnte, statt bei einem falschen Format einfach abzubrechen und den Nutzer die Chance zu geben, den Fehler zu korrigieren.

Dein Code hat nämlich einen riesigen Bug, den Du dank Deiner Robustheit einfach niederbügelst.

Code: Alles auswählen

n [2]: parse('3.2.2021')
Out[2]: datetime.datetime(2021, 3, 2, 0, 0)

Eine Name ist kein bytes-Objekt. Denn alle Strings werden intern als Strings behandelt. Die Logik ist auch verquer, warum ein String immer in ein utf8-Codiertes Bytes-Objekt umgewandelt wird, mit dem man nichts sinnvolles anfangen kann, und gleichzeitig ein latin1-Codierter Name als bytes-Objekt ohne Probleme durch Deine tolle Robustheitsprüfung durchrutscht.
Ein weiterer Punkt, warum man möglichst auf explizite Typprüfung verzichten sollte: es gibt immer Typen, die man sinnvoll auch verwenden könnte, aber durch die Robustheit des Codes nicht darf, hier also bytearrays, die äquivalent zu bytes-Objekten sind.

Da schreib ich lieber fehlerfreien Code als robusten Code.

Re: Kommandos inkommensurabel

Verfasst: Freitag 28. Mai 2021, 14:24
von pillmuncher
Wer glaubt, er hätte Datums- & Uhrzeitprogrammierung verstanden, hat Datums- & Uhrzeitprogrammierung nicht verstanden.
Falsehoods programmers believe about time
Ein Programm, das angesichts all dieser Fallstricke zu erraten versucht, was mit einem Datums-String gemeint sein könnte, ist nicht robust, sondern "robust".
Von den Problemen mit Encodings gar nicht zu reden.

Re: Kommandos inkommensurabel

Verfasst: Freitag 28. Mai 2021, 14:43
von LukeNukem
narpfel hat geschrieben: Freitag 28. Mai 2021, 13:27 @LukeNukem: Das automatische Parsen sieht für mich nach einem Rezept für Datums-Mojibake aus. Woher weiß dein Programm, ob "01/02/03" entweder 2001-02-03, 2003-01-02 oder 2003-02-01 ist? Und wie ist das „korrekt und robust“?
Du hast Recht, daß das mehrdeutig ist, allerdings würde dabei 2003-01-02 herauskommen, was IMHO in fast allen Fällen auch vollkommen richtig sein dürfte. Andererseits ist die Mehrdeutigkeit halt so ein Grundproblem bei zweistelligen Jahreszahlen; vermutlich hab' ich auch deswegen schon seit Ewigkeiten keine mehr gesehen. Wie dem auch sei, dafür kennt dateutil.parser.parse() ja eigens die Parameter "dayfirst" und "yearfirst", mit denen sich dieses Verhalten beeinflussen läßt. Weg mag, kann die Konstruktoren ja so abändern, daß sie optionale "**kwargs" akzeptieren und diese dann an den Aufruf von datetime.parser.parse() durchreichen -- ich möchte aber jetzt nicht wegen fünf geänderter Zeilen nochmal den ganzen Code posten, zumal die Änderungen ja mehr als trivial sind. ;-)

Andere Alternativen wären die Module "dateparser" oder "Arrow", oder natürlich ein Eigenbau, der verschiedene Formate mit datetime.datetime.strptime() durchprobiert.

Übrigens gefällt mir auch der Vorschlag von kbr sehr gut, das in eine separate Funktion auszulagern, die dann allerdings -- notwendigenfalls parametrierbar -- im Konstruktor aufgerufen würde. Gute Idee und ein prima Tipp für unseren TO, sehr schick!

Re: Kommandos inkommensurabel

Verfasst: Freitag 28. Mai 2021, 14:51
von LukeNukem
pillmuncher hat geschrieben: Freitag 28. Mai 2021, 14:24 Wer glaubt, er hätte Datums- & Uhrzeitprogrammierung verstanden, hat Datums- & Uhrzeitprogrammierung nicht verstanden.
Falsehoods programmers believe about time
Daraus:
Don't re-invent a date time library yourself. If you think you understand everything about time, you're probably doing it wrong.
Deswegen benutze ich für sowas gerne dateutil, das nach > 15 Jahren Entwicklung vermutlich eine gewisse Reife erreicht haben dürfte. :-)

Re: Kommandos inkommensurabel

Verfasst: Freitag 28. Mai 2021, 16:07
von kbr
@hcshm: Als Ergänzung zum Konverter: ich würde den Konverter auf keinen Fall im Konstruktor aufrufen, wobei in dieser Diskussion wohl der Initialisator gemeint sein dürfte – aber auch dort würde ich das vermeiden. Weiter würde ich ihn auch nicht bei der Argumentübergabe an die Klasse zur Instanziierung einbinden, da dies die Fehlerbehandlung undurchsichtiger machen kann. Stattdessen würde ich die Konvertierung als separaten Schritt zuvor vornehmen; gegebenenfalls mit einer nachfolgenden Validierung, sofern eine solche erforderlich ist – und nachdem der gewünschte Datentyp vorliegt.

Der Konverter darf auch vernünftige Annahmen über den Eingabedatentyp, als auch bei Strings über das Format machen. Sonst ist die Aufgabe bei mehrdeutigen Eingaben nicht möglich. Eine Konvertierung kann nicht mit allen möglichen beliebigen Eingabeformaten und -typen fehlerfrei funktionieren. Also besser einfache Konverter mit klar definiertem erlaubten Input.

Wenn all das beherzigt wird, kann dies zu kurzem, lesbaren und testbaren, sowie effizienten Code führen.

Re: Kommandos inkommensurabel

Verfasst: Freitag 28. Mai 2021, 16:41
von __blackjack__
Statt dem eigenen `ConversionError` wäre ein `TypeError` in den gezeigten Fällen sinnvoller, denn genau das wird damit dort ja angezeigt, das der Code den Typ nicht kennt und deshalb nicht will. Was letztlich „duck typing“ verhindert und damit nicht pythonisch ist.

Alles mögliche überall für den Aufrufer auf Verdacht umzuwandeln führt zu Code-Duplikationen, zu mehr Angriffsfläche für Fehler, zu mehr Tests die man schreiben muss, und in der Praxis wird sehr wahrscheinlich vieles davon am Ende überhaupt nicht verwendet.

Das der Name am Ende als `bytes` endet, statt als Zeichenkette, ist vermute ich mal ein Flüchtigkeitsfehler und sollte andersherum.

In `Ding.__init__()` fehlt der `super()`-Aufruf. Oder der Hinweis, dass man das nicht sicher mit Mehrfachvererbung verwenden kann. Und durchgereichte *args und **kwargs. Oder der Hinweis das man in abgeleiteten Klassen die Signatur nicht erweitern darf oder eben auch wieder Probleme bei Mehrfachvererbung drohen.

Beim Validieren vom Geburtstagswertebereich hat Python die praktische Operatorverkettung, so dass der Teil der in beiden Verhleichen verwendet wird, nur einmal geschrieben und ausgewertet werden muss.

In Produktiv-Code würde ich das `attr`-Modul verwenden. Das vereinfacht/beseitigt die `__init__()` und bietet hooks für Validierung. Spart also hier die Extraklasse und damit dann auch den Namenszusatz `Valid…` bei jeder Klasse wenn man das Muster konsequent durchzieht. Sollte man dieses Muster verwenden, würde ich den Namenszusatz zu der unvalidierten Klasse verschieben. `attr` verringert auch Codewiederholungen beim Validieren wenn man die Möglichkeit nutzt Validierungsfunktionen zu schreiben.

Re: Kommandos inkommensurabel

Verfasst: Freitag 28. Mai 2021, 20:52
von LukeNukem
__blackjack__ hat geschrieben: Freitag 28. Mai 2021, 16:41 Statt dem eigenen `ConversionError` wäre ein `TypeError` in den gezeigten Fällen sinnvoller, [...]
Alles richtig, stimmt... wobei ich den ConversionError schon wegen des zusätzlichen Informationsgehalts behalten wollen würde, aber vermutlich besser von TypeError geerbt hätte.

Ganz besonders freue ich mich darüber, daß es auch konstruktiv geht. Danke.

Re: Kommandos inkommensurabel

Verfasst: Samstag 29. Mai 2021, 05:59
von hcshm
ganz herzlichen Dank, das waren zahlreiche, enorm wichtige Gedankenanstöße!!