[Im Aufbau] benchmark.py

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 10. November 2006, 10:38

Zum Thema "private-Mechanismus" geht weiter unter: http://www.python-forum.de/topic-7790.html

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Freitag 10. November 2006, 13:49

benchmark.py v1.0.2 beta: http://lodgeit.lucumr.pocoo.org/show/79/

Bin fertig. Sollte jetzt alles den Richtlinien von PEP8 entsprechen.

GetRanking gibts nun nicht mehr. Hab das so gelöst: Nach dem in run() die Laufzeit untersucht wurde, wird danach das ranking erzeugt und in self.ranking gespeichert. Damit spare ich mir nen Gettert ;) self.ranking ist ein list von dicts => [{}, {}, ...]

print_ranking() gibt das ranking aus. Falls aber run() nicht ausgeführt wurde und gleich print_ranking() benutzt wird, wird eine Exception ausgelöst, die auf den Fehler hinweist. Ist mMn gut gelöst, weil stattdessen ein IndexError ausgelöst werden würde, da ja self.ranking ohne run() leer bleibt ;) benchmark.py ist aber gut dokumentiert und die main() wurde um alle möglichen Beispielen erweitert.

@Leo: Habe alles nach deinen Vorschlägen geändert bis auf folgendes:
Zeile 154: self._data[0][0], [0][0] sieht sehr nichtssagend aus, vielleicht kann an hier eine andere Datenstruktur verwenden? Zum Beipiel ein Dict, mit einer Listen innen drin, oder sowas ähnliches?
Hier kann ich nicht die Datenstruktur ändern. Das ganze basisiert darauf dass alles in die Liste gepusht wird, und danach die liste nach der Zeit (die sich jeweils auf Index 0 befindet) sortiert wird. Wenn ich nun ein dict machen würde dann würde es nur nach den Key sortiert und daher unbrauchbar. Hab das getestet und daher mache ich das so => [[], [], []]
Das spielt ja aber auch keine rolle, da es intern ist (und nur temporär) und nachher alles als list von dicts in self.ranking gespeichert wird => [{}, {}, …]. :)

lg
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 10. November 2006, 13:57

IMHO sind die eigenen Fehlerklassen unnötig!

Code: Alles auswählen

    def print_ranking(self):
        """Diese Methode zeigt das Ranking an stdout an."""
        if not self.ranking:
            raise NoValueError("Das Attribut ranking von %s enthaelt keine"
                               " Daten!\n" 
                               "Folgende Methode/Funktion hat die"
                               " Exception ausgeloest: %s"
                               % (self, self.print_ranking)
                              )
Warum nicht an der stelle einen normalen ValueError werfen? Dann kann man sich die eigenen Fehler-Klassen Zeile 39-51 komplett sparen. Ich würde es so machen:

Code: Alles auswählen

    def print_ranking(self):
        """Diese Methode zeigt das Ranking an stdout an."""
        if not self.ranking:
            raise ValueError(
                "Keine Daten vorhanden,"
                " da Benchmark noch nicht ausgeführt wurde!"
            )
Ein del(bench) vor einem bench = Benchmark() ist überflüssig. Zeile 207 und 218

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 10. November 2006, 14:01


CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Freitag 10. November 2006, 15:10

Hier die neue version: http://paste.pocoo.org/show/82/
diff: http://paste.pocoo.org/compare/81/
P.S.: Die docstring muss ich noch anpassen für die exceptions. Ging jetzt nicht auf die schnelle.

----

Ne, das sehe ich anders. Es geht ja gerade um die Differenzierung von Fehlern.

Hier ein Beispiel (Hab die Klasse erweitert):

angenommen wir übergeben statt einer Funktion eine Variable als Referenz…

Code: Alles auswählen

a = 0
bench = Benchmark()
bench.add_function(a, "LC", loops)
[…]
…dann kommt folgender traceback beim ausführen von add_function() der nichts sagend ist und wohlmöglich als Unterstellung genutzt werden könnte, das man keine richtige Fehlerüberprüfung implementiert hat (zu recht!)-->

Code: Alles auswählen

self._functions.append([ref.__name__, comment, ref, args])
AttributeError: 'int' object has no attribute '__name__'
So, nun implementiere ich in add_function eine Überprüfung:

Code: Alles auswählen

if str(type(ref)) != "<type 'function'>":
            raise WrongArgumentError("Das uebergeben Argument an ref ist " 
                                     "keine Referenz auf eine Funktion!")
Nun der gleiche aufruf:

Code: Alles auswählen

a = 0
bench = Benchmark()
bench.add_function(a, "LC", loops)
[…]
Traceback:

Code: Alles auswählen

  raise WrongArgumentError("Das uebergeben Argument an ref ist " 
__main__.WrongArgumentError: Das uebergeben Argument an ref ist keine Referenz auf eine Funktion!
Das ist schon viel aussagekräftiger :)

Genauso verhält es sich mit ValueError, das kein Bestandteil des Moduls ist. Warum so was benutzen, wenn es doch transparenter geht in dem ich dafür eine Eigene Exception definiere? Was passiert wenn irgendwas anderes im Try Block einen ValueError auslöst, das nichts mit meine Modul zu tun hat? Dann würde ich das wohl möglich abfangen und eine total falsche Fehlerbehandlung machen ;) Weist du was ich meine? Dan lieber eine eigen Exception die dafür sorgt das _nur_ die exceptions, im _pasenden_ except-block, abgefangen werden die von _meinen_ Modul ausgelöst werden.

Außerdem, geht es doch darum das man für jeden Fehler eine eigene passende Fehlerbehandlung macht. Das ist aber nicht möglich wen ich eine fremde Exception benutze, die mit meinem Modul nichts zu tun hat und dann auf einmal ne exception von irgendwo anders kommt und im gleichen except_block abgefangen werden, wo sie aber _nicht_ abgefangen werden dürfen! ;)

EDIT: im main() ist ein Beispiel.
BlackJack

Freitag 10. November 2006, 16:07

XtraNine hat geschrieben:So, nun implementiere ich in add_function eine Überprüfung:

Code: Alles auswählen

if str(type(ref)) != "<type 'function'>":
            raise WrongArgumentError("Das uebergeben Argument an ref ist " 
                                     "keine Referenz auf eine Funktion!")
Es ist nicht garantiert das die Zeichenkette vom Funktionstyp immer so aussieht und Du verhinderst damit das etwas anderes als Funktionen übergeben wird. Methoden werden zurückgewiesen und auch Objekte die `__call__()` implementieren. Beides unnötige Einschränkungen. Versuchs mal mit:

Code: Alles auswählen

if not callable(ref):
    raise TypeError('ref is not callable')
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Freitag 10. November 2006, 17:15

104beta - http://paste.pocoo.org/show/83/

...

@jens: OK, hab das durch ValueError ersetzt. Dan darf man halt nicht alles in einen Try-Block packen...Ist vielleicht auch pythonischer wenn man nicht alles in einem Try-Block drin hat.

@BlackJack:
Hab ich hinzugefügt. Hab auch das TypeError zum raisen genommen.

Ich weiß das es ein wenig OT ist: Wie viel sollte man eigentlich überprüfen? Ich denke mit ref sollte das noch ok sein, damit nicht der traceback…

Code: Alles auswählen

self._functions.append([ref.__name__, comment, ref, args]) 
AttributeError: 'int' object has no attribute '__name__'
…abgezeigt wird, sondern ein eigener. Obwohl eigentlich der Benutzter selber dafür sorge tragen sollte das er die Klasse/Methode richtig benutzt.

Das bringt mich dann auf die frage: Wie viel sollte man selber schon als Fehlerüberprüfung für Argumente oder den Inhalt der Argumente implementieren? Wer trägt eigentlich die Verantwortung? -> Der jenige der die Klasse schreibt und es nach _seinen vorgaben_ 100%ig funktioniert oder der Jenige der die Klasse nach _abweichenden vorgaben_ benutzt und somit Fehler produziert. Sollte man für letzteres trotzdem eine eigene Fehlermeldung ausgegeben werden oder sollte man so stur sein und sich denken "Verdammt noch mal benutzt die Klasse so wie ich sie beschreiben habe und RTFM!"

Wie sieht ihr das Thema? Ich persönlich würde ja für jede mögliche Unwägbarkeit ne eigen exception auslösen, damit der Benutzer bei Falscher Benutzung einen Feedback erhält. Oder sollte ich mich da von dem C++ Dogma gänzlich lösen. Was ist Pythonischer?

Auch das Thema keine eigenen Exception Klassen zu implementiere, sonder schon passende vorhanden zu nutzen (wie im Beispiel mit ValueError und TypeError) hat mich ein wenig verunsichert. :?

lg

Edit (Leonidas): Thread kann aufgrund von Softwarebugs leider an dieser Stelle nicht mehr weitergeführt werden (daher geschlossen), dafür bitte den neuen Thread verwenden. Sorry für die Unbequemlichkeiten.
Gesperrt