Seite 1 von 1

Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 11:36
von CM
Hoi,

eigentlich soll meine Applikation von mir was folgt mehr oder weniger automatisch berechnen, aber Nutzer sollen doch auch die Möglichkeit bekommen einen Sack voll Paramter per Hand an eine Funktion zu geben. So ein Haufen Paramter kann, je nach Fragestellung an das Programm rel. lang aussehen, z. B. so:

Code: Alles auswählen

{'A': {'phi': 8, 'psi': -6, 'dz': 4, 'dx': -1.0, 'dy': -5, 'theta': 2.0}, 'C': {'phi': 8, 'psi': 8, 'dz': 5, 'dx': 5, 'dy': -5, 'theta': 8}, 'B': {'phi': 0, 'psi': 6, 'dz': -5, 'dx': 5, 'dy': 5, 'theta': 8}, 'E': {'phi': 4, 'psi': 0, 'dz': 5, 'dx': 2, 'dy': 5, 'theta': 8}, 'D': {'phi': 8, 'psi': 8, 'dz': 5, 'dx': 4, 'dy': -4, 'theta': -2}, 'G': {'phi': 8, 'psi': 8, 'dz': 1, 'dx': 5, 'dy': -1.0, 'theta': 8}, 'F': {'phi': 0, 'psi': 8, 'dz': -5, 'dx': 5, 'dy': -2, 'theta': 8}, 'H': {'phi': 8, 'psi': 6, 'dz': 5, 'dx': 4, 'dy': 5, 'theta': 8}}
Das von Hand einzugeben, ist also wirklich nur die letzte Lösung, aber das Angebot richtet sich auch dahingehend, das Nutzer der Programms aus einem Logfile schnell mal was visualisieren können - wenn sie es wollen. Allerdings ist es natürlich leicht passiert, das hier bei der Eingabe ein Fehler unterläuft, also steht in einer Funktion - daher die weite Einrückung - folgender Code:

Code: Alles auswählen

        if move:
            # check at least whether move is a dict
            if not isinstance(move, dict):
                raise AssertionError("given parameter 'move' is no dictionary, see documentation for" +
                                                " further details")
            for chain, params in move.iteritems():
                if not isinstance(params, dict):
                    raise AssertionError("entry for chain %s is no dictionary" % chain)
                for param, value in params.iteritems():
                    if not isinstance(value, (float, int)):
                        raise AssertionError("entry for %s in chain %s is not number (float or int)" %
                                                             (param, chain))
Meine Frage: Gibt es für dieses Konstrukt auch eine Abkürzung? Es sieht so unschön aus ...

Gruß,
Christian

Verfasst: Donnerstag 11. Oktober 2007, 11:43
von lutz.horn
Greif doch einfach mit get() auf das vermutete Dictionary zu. Falls move kein Dictionary ist, wird ja ein AttributeError geworfen. Ebenso werfen int(x) und float(x) einen ValueError, falls ihr Argument nicht verarbeitet werden kann.

Siehe auch http://de.wikipedia.org/wiki/Dynamische ... uck_Typing

Der Nachteil dabei ist natürlich, dass nicht die anwendungsspezifischen Fehlertexte ausgegeben werden.

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 11:53
von helduel
Moin!
CM hat geschrieben:Meine Frage: Gibt es für dieses Konstrukt auch eine Abkürzung? Es sieht so unschön aus ...

Code: Alles auswählen

assert isinstance(move, dict),'move is no dictionary'
So umgehst du das ganze if/raise-Zeugs. Ansonsten kann ich auch nur empfehlen, nicht alles überprüfen zu wollen. Lieber an den richtigen Stellen auftretende Exceptions abfangen, wie das lutz.horn empfohlen hat.

Gruß,
Manuel

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 11:55
von gerold
CM hat geschrieben:Gibt es für dieses Konstrukt auch eine Abkürzung?
Hallo Christian!

Eine Abkürzung ist das hier nicht unbedingt, aber es ist sicher schneller als die vielen Tests die du machst. Hier wird nur mehr darauf reagiert, wenn sich die Daten nicht wie gewünscht verhalten. Es wird nicht vorausgesetzt dass es Dictionaries sind. So lange sie sich wie Dictionaries verhalten ist alles in Ordnung.

Code: Alles auswählen

if move:
    try:
        for chain, params in move.iteritems():
            try:
                for param, value in params.iteritems():
                    value = float(value)
                    # ...
                    # ...
            except AttributeError:
                raise AssertionError("entry for chain %s is no dictionary" % chain)
            except ValueError:
                raise AssertionError(
                    "entry for %s in chain %s is not number (float or int)" %
                    (param, chain)
                )
    except AttributeError:
        raise AssertionError(
            "given parameter 'move' is no dictionary, see documentation for "
            "further details"
        )
Vielleicht kannst du ja etwas damit anfangen.

lg
Gerold
:-)

Verfasst: Donnerstag 11. Oktober 2007, 12:00
von CM
lutz.horn hat geschrieben:Der Nachteil dabei ist natürlich, dass nicht die anwendungsspezifischen Fehlertexte ausgegeben werden.
Gut, das sollte aber der Fall sein - der Nutzer soll nicht unbedingt Python *können* müssen - und das Ganze soll rel. idiotensicher sein.
Im Übrigen sollte ich wohl hinzufügen, daß das dict u. a. deshalb so kompliziert ist, um auf der anderen Seite möglichst flexibel rechnen zu können. Wie man vielleicht sehen kann, sind die Parameter Bewegungsparamter und mein Ziel ist es für die Chains ('A', 'B', usw.) jede (!) Symmetrie abbilden zu können, die diese Partikel einnehmen können - nicht nur Schönfliessymmetrien. Das heißt leider auch sogar, daß es keinen Chain 'A' geben muß. Die Bennennung ist willkürlich. Was soll ich also mit get() holen? (Ich könnte natürlich erst testen: dict, ja oder nein? Und dann ggf. mit keys auf die Schlüssel zugreifen - aber das ist genauso umständlich, wie der Code, der da steht.)

Gruß,
Christian

Verfasst: Donnerstag 11. Oktober 2007, 12:01
von CM
Ah, Gerold, das ist eine gute Idee! Kürze ist vielleicht nicht so entscheidend, aber Dein Snippet ist deutlich eleganter ;-).

Merci,
Christian

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 12:27
von EyDu
helduel hat geschrieben:

Code: Alles auswählen

assert isinstance(move, dict),'move is no dictionary'
So umgehst du das ganze if/raise-Zeugs.
"assert" ist nur zum Testen gedacht und nicht zum Implementieren von Logik, da beispielsweise bei Erzeugung von optimiertem Code alle assert-Statements entfernt werden.

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 12:36
von CM
helduel hat geschrieben:Ansonsten kann ich auch nur empfehlen, nicht alles überprüfen zu wollen.
Sorry, aber hier muß ich noch mal Stellung nehmen: Das mache ich doch, da - wie beschrieben - es sich um eine an einen pot. Nutzer einer Applikation gerichtete Eingabefunktion handelt. Wenn ich nicht an der Stelle fehlerhafte Eingaben mit sinnvollen Meldungen abfange, dann kann ein unbedarfter Nutzer mit einem laaangen Traceback konfrontiert werden, bei dem dann stünde, daß in einer Funktion _rotate() (Man beachte das '_' das absichtlich voransteht, weil es sich um etwas handelt, wo ich absichtsvoll einen Wrapper drumgebastelt habe.) ein Fehler auftrat. Und dann soll dieser Nutzer den Fehler finden können? Die Mailinglisten sind voll von Anfrage à la: "Ich habe da dieses ewiglange Traceback: Ist das ein Bug in eurer Software? Wo liegt der / mein Fehler? usw."
DAS zeugt ggf. von schlechtem Design. Insbesondere, wenn es sich um rechenintensive Software handelt, wo der Traceback dann im Zweifelsfall erst nach geraumer Zeit kommt - insofern muß ich auch noch mal darüber nachdenken, ob ich Gerolds Lösung tatsächlich so gut für mich finde. (Wußte doch, daß ich mir was dabei gedacht hatte nicht mit try/except zu arbeiten ... gehört unbedingt als Kommentar rein, wenn ich mich gegen Gerolds Version entscheide.)
Schlechte pythonbasierte Beispiele mit Mailinglisten mit entsprechenden Anfragen:
http://www.salilab.org/modeller/
http://autodock.scripps.edu/
(Beides tolle Programme, aber Fehlersuche kann z. T. furchbar sein.)
Look before you leap ist rel. unpythonisch, kann aber doch manchmal sinnvoll sein - daher mein langes Plädoyer (obwohl wirklich erst noch überlegen muß, was bei meinem Programm am besten ist).

Zu dem "assert" sage ich jetzt mal nichts - wie ich sehe hat das zwischenzeitlich schon ein Anderer getan ... ;-)

Gruß,
Christian

Verfasst: Donnerstag 11. Oktober 2007, 12:54
von BlackJack
Vielleicht könntest Du das von der Funktion trennen und eine Extrafunktion zum überprüfen der Benutzereingabe einfügen. Benutzereingaben muss man natürlich so gut wie möglich überprüfen, man ahnt ja meist gar nicht auf was für Ideen die so kommen können. ;-)

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 13:13
von Zap
EyDu hat geschrieben:"assert" ist nur zum Testen gedacht und nicht zum Implementieren von Logik, da beispielsweise bei Erzeugung von optimiertem Code alle assert-Statements entfernt werden.
Wo kann man mehr über diese Verhaltensweise erfahren?!
Von welcher Optimierung redest du? Gibt's automatisierte Optimierungen die das in der Realität machen?

Ich bin hier und da durchaus geneigt asserts einzubauen
sollte man stattdessen lieber "if foo: raise MyException("bar") " verwenden?
Finde ich auch nicht wirklich optimal weil manchmal Kontrollen nichts anderes für mich sein sollten als "asserts".

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 13:30
von EyDu
Zap hat geschrieben:Wo kann man mehr über diese Verhaltensweise erfahren?!
Von welcher Optimierung redest du? Gibt's automatisierte Optimierungen die das in der Realität machen?[/qoute]
Lies dir hier dazu einfach mal den letzen Absatz durch.
Zap hat geschrieben:Ich bin hier und da durchaus geneigt asserts einzubauen
sollte man stattdessen lieber "if foo: raise MyException("bar") " verwenden?
Wenn du die asserts dazu verwendet zu prüfen ob dein Programm korrekt funktioniert (automatische Tests, Unittests, ...) verwendest du sie richtig. Jede andere Verwendung ist nicht sinnvoll.

Dient die Überprüfung hingegen deinem Programm, so ist ein "if...: raise..." die richtige Wahl.

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 13:32
von birkenfeld
CM hat geschrieben: Sorry, aber hier muß ich noch mal Stellung nehmen: Das mache ich doch, da - wie beschrieben - es sich um eine an einen pot. Nutzer einer Applikation gerichtete Eingabefunktion handelt.
Wenn der Nutzer falsche *Typen* (nicht Werte) übergeben kann, ist er Programmierer, denn dann hat er Code geschrieben, der mit deinem interagiert. Dann aber kann man zumindest verlangen, dass er die Dokumentation liest (die wiederum hoffentlich für öffentliche Schnittstellen existiert).

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 13:34
von helduel
CM hat geschrieben:
helduel hat geschrieben:Ansonsten kann ich auch nur empfehlen, nicht alles überprüfen zu wollen.
[...]
DAS zeugt ggf. von schlechtem Design. Insbesondere, wenn es sich um rechenintensive Software handelt, wo der Traceback dann im Zweifelsfall erst nach geraumer Zeit kommt - insofern muß ich auch noch mal darüber nachdenken, ob ich Gerolds Lösung tatsächlich so gut für mich finde. (Wußte doch, daß ich mir was dabei gedacht hatte nicht mit try/except zu arbeiten ... gehört unbedingt als Kommentar rein, wenn ich mich gegen Gerolds Version entscheide.)
[...]
Zu dem "assert" sage ich jetzt mal nichts - wie ich sehe hat das zwischenzeitlich schon ein Anderer getan ... ;-)
Da habe ich wohl deinen Code-Schnipsel nicht richtig verstanden. Natürlich ist 'assert' nur zum Testen da. Ich ging nicht davon aus, dass der User sich darum kümmern soll, dass die Daten irgendwie ordentlich in Dictionaries verpackt daherkommen, sondern dass das deine Applikation macht. Deswegen meinte ich, nicht alles überprüfen.

Gruß,
Manuel

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 13:34
von birkenfeld
EyDu hat geschrieben: Lies dir hier dazu einfach mal den letzen Absatz durch.
Warum verlinkst du gegen die Doku zu 1.5.2? Das hier wäre wesentlich aktueller.

@Zap: Gemeint ist hier die "Optimierung", die beim Aufruf von python -O durchgeführt wird.

Re: Vereinfachtes "Typechecking" möglich?

Verfasst: Donnerstag 11. Oktober 2007, 13:48
von EyDu
birkenfeld hat geschrieben:Warum verlinkst du gegen die Doku zu 1.5.2?
Und genau so etwas passiert, wenn man Dokumentation über Google sucht und den Ergebnissen einfach mal blind vertraut :roll:

Ich werde die aktuelle Doku dann einfach mal in meine Favoriten legen.

Verfasst: Donnerstag 11. Oktober 2007, 14:36
von CM
BlackJack hat geschrieben:Vielleicht könntest Du das von der Funktion trennen und eine Extrafunktion zum überprüfen der Benutzereingabe einfügen. Benutzereingaben muss man natürlich so gut wie möglich überprüfen, man ahnt ja meist gar nicht auf was für Ideen die so kommen können. ;-)
Oh, jaaa :roll:
Aber bisher ist die in Frage kommende Funktion die Einzige, die zu diesen rel. low-level-Zugriff ermuntert. ... Prinzipiell aber hast Du recht: Auch das sollte ich überdenken. Danke.
birkenfeld hat geschrieben:Wenn der Nutzer falsche *Typen* (nicht Werte) übergeben kann, ist er Programmierer, denn dann hat er Code geschrieben, der mit deinem interagiert. Dann aber kann man zumindest verlangen, dass er die Dokumentation liest (die wiederum hoffentlich für öffentliche Schnittstellen existiert).
Berechtigter Einwand, aber meine pot. Nutzer sind Wissenschaftler, die alle glauben programmieren zu können und ungerne Doku lesen ... ;-) (die Doku erstelle ich gerade erst :oops: )
helduel hat geschrieben:Ich ging nicht davon aus, dass der User sich darum kümmern soll, dass die Daten irgendwie ordentlich in Dictionaries verpackt daherkommen, sondern dass das deine Applikation macht.
meine Antwort
CM hat geschrieben:eigentlich soll meine Applikation von mir was folgt mehr oder weniger automatisch berechnen, aber Nutzer sollen doch auch die Möglichkeit bekommen einen Sack voll Paramter per Hand an eine Funktion zu geben.
Anstelle von "eine Funktion" sollte es wohl "eine bestimmte Funktion" lauten. Aber die Diskussion und meine Antworten leiten mich zum Gedanken, daß ich auch an der Stelle das Design überdenken sollte ...

Auweia, hätte ich gewußt, daß ich sooo eine Diskussion losschiebe ... ist aber eigentlich ganz interessant.

Gruß,
Christian

Verfasst: Donnerstag 11. Oktober 2007, 15:12
von birkenfeld
birkenfeld hat geschrieben:Wenn der Nutzer falsche *Typen* (nicht Werte) übergeben kann, ist er Programmierer, denn dann hat er Code geschrieben, der mit deinem interagiert. Dann aber kann man zumindest verlangen, dass er die Dokumentation liest (die wiederum hoffentlich für öffentliche Schnittstellen existiert).
Berechtigter Einwand, aber meine pot. Nutzer sind Wissenschaftler, die alle glauben programmieren zu können und ungerne Doku lesen ... ;-) (die Doku erstelle ich gerade erst :oops: )
[/quote]

In dem Fall wäre aber auch eine saubere Lösung z.B. mit Dekoratoren gut:

Code: Alles auswählen

@takes(str, dict)
def foo(...)
Das hat den Vorteil, dass sich der Overhead fürs Typen prüfen trivial abschalten lässt, indem man nur `takes` umdefiniert.

Verfasst: Donnerstag 11. Oktober 2007, 16:56
von CM
Das ist in der Tat eine interessante Option, aber ich muß zugeben: Hier stoßen meine Pythonfähigkeiten seit langem wieder an eine Grenze. Wie müßte denn takes aussehen, wenn

Code: Alles auswählen

def foo(self, par0, par1=default_integer, par2=default_list, par3=verschachteltes_default_dict):
mit par0 einem x-beliebigen Argument entsprechend, z. B. ein String (weil der in der Auflistung fehlt ;-) ).

Außerdem, und hier wird es wichtig, wie sieht es mit Dekoratoren in Python 3k aus? Ich habe gesucht und nichts gefunden, vermute aber, daß ich bloß zu blöd zum finden war ...

Gruß,
Christian

Verfasst: Donnerstag 11. Oktober 2007, 21:47
von birkenfeld
CM hat geschrieben:Das ist in der Tat eine interessante Option, aber ich muß zugeben: Hier stoßen meine Pythonfähigkeiten seit langem wieder an eine Grenze. Wie müßte denn takes aussehen, wenn

Code: Alles auswählen

def foo(self, par0, par1=default_integer, par2=default_list, par3=verschachteltes_default_dict):
mit par0 einem x-beliebigen Argument entsprechend, z. B. ein String (weil der in der Auflistung fehlt ;-) ).
Da muss man sich halt entsprechende Notationen einfallen lassen.
Außerdem, und hier wird es wichtig, wie sieht es mit Dekoratoren in Python 3k aus? Ich habe gesucht und nichts gefunden, vermute aber, daß ich bloß zu blöd zum finden war ...
Es wird sie weiterhin in der gewohnten Form geben, zusätzlich auch als Klassendekoratoren.