Läute ihr bringt mich wider auf eine Idee xD Wäre es nicht vielleicht gut, noch einzubauen wie viel Prozent die CPU ausgelastet wird, und das dann im Ranking anzeigen zu lassen? Gibt es in Python dafür ein Standard Modul?
lg
Seit 2002 Diskussionen rund um die Programmiersprache Python
https://www.python-forum.de/
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# Coding by jens, BlackJack und XtraNine @www.python-forum.de
#
# Dank geht an jens, BlackJack und allen anderen aus diesem Thread,
# die mir dabei geholfen haben:
# http://www.python-forum.de/viewtopic.php?p=48410#48410
#
# LG XtraNine
import time
class Benchmark:
def __init__(self):
self._functions = []
self.data = []
self.refTime = 0.0
def AddFunc(self, ref, comment, *args):
self._functions.append( [ref.__name__, comment, ref, args] )
def Run(self):
for name, comment, ref, args in self._functions:
print "run: %10s - %-10s" % (name, comment),
t1 = time.clock()
ref(*args)
t2 = time.clock() - t1
self.data.append([t2, comment, name])
print "OK (%.2fsec.)" % t2
self.data.sort(reverse=True)
self.refTime = bench.data[0][0]
print "-"*80
def PrintRanking(self):
print "Funktion: %10s - %-10s ist am langsamste; Zeit %f sec" %(
self.data[0][2], self.data[0][1], self.data[0][0]
)
for t, comment, name in self.data[1:]:
percent = (100*self.refTime/t) - 100
print "Funktion: %10s - %-10s ist um %.2f%% schneller; Zeit %f sec" % (
name, comment, percent, t
)
if __name__ == '__main__':
def f1(loops):
list = [str(i) for i in xrange(loops)]
def f2(loops):
list = []
for i in xrange(loops):
list.append(str(i))
def f3(loops):
list = []
for i in range(loops):
list.append(str(i))
loops = 1000000
bench = Benchmark()
bench.AddFunc(f1, "LC", loops)
bench.AddFunc(f2, "xrange", loops)
bench.AddFunc(f3, "range", loops)
bench.Run()
bench.PrintRanking()
Code: Alles auswählen
run: f1 - LC OK (1.21sec.)
run: f2 - xrange OK (1.44sec.)
run: f3 - range OK (1.48sec.)
--------------------------------------------------------------------------------
Funktion: f3 - range ist am langsamste; Zeit 1.478379 sec
Funktion: f2 - xrange ist um 2.88% schneller; Zeit 1.437011 sec
Funktion: f1 - LC ist um 22.50% schneller; Zeit 1.206814 sec
Genau das wollte ich grade anmängeln. Aber wxPython gilt nicht als Ausrede, denn wxPython ist ein dünner Wrapper um wxWidgets, von dem es das CamelCase erbt. Als Vorbildfunktion kann die API von wxPython auch nicht dienen, denn wxPython hat eine sehr unpythonische und wenig angenehme API (die sich eben nach C++ "anfühlt").XtraNine hat geschrieben:BTW: Ich weiß das sich die Namen der Methoden nicht an PEP8 halten, die man ja alle lowercase und underscores benenn soll, aber mir gefällt es so besser und wxPython macht es ja auch so ^^
Ja, ich guck gleich rein.XtraNine hat geschrieben:Hab übrigens zu PEP8 nen Thread open: http://www.python-forum.de/topic-7781.h ... hlight=24h
Das # EOF am ende finde ich etwas blöd, ansonsten fände ich es besser, wenn du in den DocStrings reST verwendest, denn diese Docutils-Syntax sieht beim lesen im Plaintext etwas seltsam aus.XtraNine hat geschrieben:Leo, Aber der Rest stimmt vom Modul oder sind da viel Sachen die noch nciht gut sind?
Das ist der No-Paste-Service von blackbird, der Django und Pygments (wieder ein Projekt von birkenfeld und blackbird) verwendet. Den finde ich so gelungen, dass ich den jetzt zum offiziellen No-Paste-Services dieses Forums erkläre. Werde keinen zwingen ihn zu nutzen, ich kann aber dazu raten, denn es funktionier superXtraNine hat geschrieben:EDIT: Was ist den LodgeIt? Muss man sich da anmelden und kann dann Code veröffentlichen? (EDIT:) --> Ok habs schon. Gute Sache
Hab gerade nach reST in wiki geschaut -> http://de.wikipedia.org/wiki/ReSTLeonidas hat geschrieben:Ja, ich guck gleich rein.XtraNine hat geschrieben:Hab übrigens zu PEP8 nen Thread open: http://www.python-forum.de/topic-7781.h ... hlight=24h
Das # EOF am ende finde ich etwas blöd, ansonsten fände ich es besser, wenn du in den DocStrings reST verwendest, denn diese Docutils-Syntax sieht beim lesen im Plaintext etwas seltsam aus.XtraNine hat geschrieben:Leo, Aber der Rest stimmt vom Modul oder sind da viel Sachen die noch nciht gut sind?
Leonidas hat geschrieben:Das ist der No-Paste-Service von blackbird, der Django und Pygments (wieder ein Projekt von birkenfeld und blackbird) verwendet. Den finde ich so gelungen, dass ich den jetzt zum offiziellen No-Paste-Services dieses Forums erkläre. Werde keinen zwingen ihn zu nutzen, ich kann aber dazu raten, denn es funktionier superXtraNine hat geschrieben:EDIT: Was ist den LodgeIt? Muss man sich da anmelden und kann dann Code veröffentlichen? (EDIT:) --> Ok habs schon. Gute Sache
Ja, genau. Denn um ehrlich zu sein, wird die Dokumentation meist im Plaintext angesehen, sei es im Editor oder durch help() und da ist dieses Markup unnötig viel "Noise".XtraNine hat geschrieben:meinst du das diese B{test}, L{GetRanking()<Benchmark.GetRanking>} Strange aussehen?
Ich finde das eigentlich schon gut, ich finde auch Annotated Haskell lustig, eine Art ausführbare Dokumentation.XtraNine hat geschrieben:Ehrlich gesagt finde ich das nicht schön, das man den Sourcecode unbedingt _im_ Sourcecode dokumentieren muss.
Gar nicht, dazu ist es eigentlich auch nicht gedacht. Aber du kannst ja blackbird fragen, ob er so ein Feature auch noch implementiert.XtraNine hat geschrieben:Super Sache Aber wie sucht man dort nach andere Sourcefiles?
Ich glaube im Moment gibt es keine Löschfunktion.XtraNine hat geschrieben:Wie lange bleiben eigentlich die Sources gespeichert? Wenn das unbegrenzt ist, dan finde ich das richtig Super
Nein, aber Lodgeit nutzt Django.XtraNine hat geschrieben:Django ist von blacky ?
Code: Alles auswählen
#!/usr/bin/python
Code: Alles auswählen
#!/usr/bin/env python
Code: Alles auswählen
BenchError (Exception)
Code: Alles auswählen
BenchmarkError(Exception)
Code: Alles auswählen
BenchmarkError(Exception): pass
In jeden Sourcefile den ich gesehen habe steht das aber so. Selbst in den Libs von Python. Warum sollte ich das jetzt ändern?Leonidas hat geschrieben:So, nun zum aktuellen Benchmark-Code:
Zeile 1:würde ich durchCode: Alles auswählen
#!/usr/bin/python
ersetzen. Ist universeller.Code: Alles auswählen
#!/usr/bin/env python
Werde ich ändern. Danke für den Hinweis. Also gilt hier der Name des Moduls (oder Klasse??) + Error als postfix?Leonidas hat geschrieben: Zeile 83: Was ist denn das? Warum ist innichtCode: Alles auswählen
BenchError (Exception)
(welches PEP8 konform und auch noch beschreibender wäre, du siehst, Exception-Namen haben kaum Abkürzungen: AttributeError statt AttrError oder E_ATTRERR).Code: Alles auswählen
BenchmarkError(Exception)
Ein pass?? Ne beim besten willen nicht. Schau mal in Zeile 251-254. Dort wird eine Exception vom Type MB_ERR_GTRG_UNKNOWNMODE ausgelöst. Es bleibt jeden selber überlassen ob der die Exception abfängt und dann den Standard text ausgibt...Leonidas hat geschrieben: Was macht die Klasse mehr als ein? Ich habe das gefühl, dass es nur unnötiger Boilerplate-Code ist. Statt Error-Codes sollte man besser andere Exceptions definieren, denn Exceptions sind ja dafür da nichtssagende Error-Codes wie 1000 zu ersetzen.Code: Alles auswählen
BenchmarkError(Exception): pass
Code: Alles auswählen
try:
[…]
data = bench.GetRanking("modus falsch")
except BenchError, err:
print err
Code: Alles auswählen
try:
[…]
data = bench.GetRanking(“modus falsch”)
except BenchError, err:
if err.errorNum == MB_ERR_GTRG_UNKNOWNMODE:
print "Der übergebene Modus an GetRanking() ist unbekannt!"
if err.errNim == xyz # dies ist noch nicht implementiert. Es soll noch für eine Methode eine Exception implementiert werden.
[…]
Ich habe gelesen und auch BlackJack (in Pythons OOP erklärt) hat gesagt das man alle Methoden und alle Attribute die nicht Public sind, mit einen unterstrich am anfange definiert. Das finde ich sinnvoll weil keiner diese Sachen anfassen soll und ich die auch nicht dokumentieren werde, wie es schon in PEP8 vorgeschlagen wird. Also self._functions, self._data, self._refTime sind für Interna bestimmt (also private) und sollen von außen _nicht_ angerührt werden. Falls ich damit falsch liege und es nicht so ist dann bitte berichtigen. Aber in dem Fall bin ich mir 100% sicher das man so Private Sachen definiert und werde es auch so beibehalten.Leonidas hat geschrieben: Zeile 108: Warum definierst du hier alles mit einem Bodenstrich? Unnötig und macht es schwerer lesbar.
Warum istLeonidas hat geschrieben: Zeile 140: nicht PEP8 kompatibel
Code: Alles auswählen
self._functions.append( [ref.__name__, comment, ref, args] )
Code: Alles auswählen
self._functions.append([ref.__name__, comment, ref, args])
Ok werde ich ändern, aber nicht als Dict mit listen drin, sonder als List mit Dicts drin, Weil...Leonidas hat geschrieben: 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?
Code: Alles auswählen
bench = Benchmark()
[...]
bench[0]['time'] # Laufzeit von Funktion 1.
bench[1]['time'] # Laufzeit von Funktion 2, etc.
[...]
Ok, danke für den hinweis. Stimmt die Leerzeichen zwischen "-" und * und 80 Fehlt.Leonidas hat geschrieben: Zeile 159: nicht PEP8 kompatibel
Zeile 168: dito
Ganz einfach wegen den Beispiel in Zeile 286:Leonidas hat geschrieben: Zeile 170: BM_GTRG_MODE_LIST finde ich völlig unnötig. Warum sollte man, wenn man schon die Möglichkeit hat, ein Dict zu bekommen, lieber eine undurchsichtige Struktur wie List haben wollen, bei der nicht sofort klar ist, welcher Index was für einen Wert repräsentiert? Klar, man kann Doku lesen, aber wenn man ein Dict hat, braucht man die Doku nicht mal anzusehen, es ist sofort klar.
Code: Alles auswählen
print "\n--- Ranking mit GetRanking() als Array von Arrays holen und ausgeben ---"
data = bench.GetRanking()
print "Funktion: %2s - %-10s ist am langsamsten; Zeit: %f sec" %(
data[0][2], data[0][1], data[0][0]
)
for time, comment, name, percent in data[1:]:
print "Funktion: %2s - %-10s ist um %.2f%% schneller; Zeit: %f sec" % (
name, comment, percent, time
)
Code: Alles auswählen
print "\n--- Ranking mit GetRanking() als Array von assoziative Arrays holen und ausgeben ---"
data = bench.GetRanking(BM_GTRG_MODE_DICT)
print "Funktion: %2s - %-10s ist am langsamsten; Zeit: %f sec" %(
data[0]['name'], data[0]['comment'], data[0]['time']
)
for dat in data[1:]:
print "Funktion: %2s - %-10s ist um %.2f%% schneller; Zeit: %f sec" % (
dat['name'], dat['comment'], dat['percent'], dat['time']
)
In jeden Sourcefile den ich gesehen habe steht das aber so. Selbst in den Libs von Python. Warum sollte ich das jetzt ändern? [/quote]XtraNine hat geschrieben:Zeile 1:würde ich durchCode: Alles auswählen
#!/usr/bin/python
ersetzen. Ist universeller.Code: Alles auswählen
#!/usr/bin/env python
Nö, hier gilt einfach die Regel "Don't use unneccessary abreviations in exception names". Und Error-Codes sollte man, wie gesagt, auch nicht verwenden.XtraNine hat geschrieben:Werde ich ändern. Danke für den Hinweis. Also gilt hier der Name des Moduls (oder Klasse??) + Error als postfix?
Ne, dort wird eine Exception vom Typ BenchError ausgelöst, die, um es noch seltsamer zu machen, noch auf den Errorcode geprüft werden muss.XtraNine hat geschrieben:Ein pass?? Ne beim besten willen nicht. Schau mal in Zeile 251-254. Dort wird eine Exception vom Type MB_ERR_GTRG_UNKNOWNMODE ausgelöst.
Nein, nein, das macht man anders:XtraNine hat geschrieben:Es bleibt jeden selber überlassen ob der die Exception abfängt und dann den Standard text ausgibt...Oder ob er das so macht:Code: Alles auswählen
try: […] data = bench.GetRanking("modus falsch") except BenchError, err: print err
Code: Alles auswählen
try: […] data = bench.GetRanking("modus falsch") except BenchError, err: if err.errorNum == MB_ERR_GTRG_UNKNOWNMODE: print "Der übergebene Modus an GetRanking() ist unbekannt!" if err.errNim == xyz # dies ist noch nicht implementiert. Es soll noch für eine Methode eine Exception implementiert werden. […]
Code: Alles auswählen
# definieren wir uns mal eine schöne Exception-Struktur
class BenchmarkError(Exception):
pass
class UnknownModeError(BenchmarkError):
pass
class ModeNotImplementedError(BenchmarkError):
pass
# wie du siehst, tun die Exceptions nichts. Brauchen sie auch gar nicht
# ich habe noch eine Exception erfunden, damit ich demonstrieren kann
# wie man "Error-Codes" in Python implementiert
# nun wollen wir mal eine Fehlerbehandlungroutine einbauen:
try:
data = bench.GetRanking(“modus falsch”)
except UnknownModeError:
print "Der Modus ist unbekannt"
except: ModeNotImplementedError:
print "Der Modus ist zwar vorhanden, aber noch nicht implementiert"
except BenchmarkError:
print "Es ist ein nicht genauer spezifizierter Benchmark-Fehler passiert (für den es keine spezielle Fehlerbehandlung gibt"
except:
print "Es ist ein absolut unerwarteter Fehler passiert"
Mein Code hat auch nur einen Try-Block und reagiert auf verschiedene Exceptions, ohne dass ich Fehlercodes auswerten muss.XtraNine hat geschrieben:Zweite Variante ist flexibler, weil man dann im try block alle Methoden verwenden kann von Benchmark und nicht in getrennten try blöcken (Zu viel code).
Kann ich so auch, spare mir sogar das Abfragen des Fehlercodes, weil Python das schon für mich macht. in GetResult muss ich nur eben die entsprechende Exception werfen, schon ist alles ok.XtraNine hat geschrieben:Und falls irgend eine Methode eine Exception auslösest kann man mit if vergleichen welcher Fehler dafür gesorgt hat. Ein anderer Vorteil ist, das man eine Individuelle Fehlermeldung ausgeben kann.
Ganz genau das. Fehlernummern machen nur sinn, wenn es wirklich viele viele verschiedene Exceptions geben kann, die nicht mehr überschaubar sind. Mit eigenen Exceptions hast du den Vorteil, dass du unglaublich fein Strukturieren kannst.XtraNine hat geschrieben:Oder willst du mir jetzt sagen das ich lieber für jeden Fehler Typ, den eine Methode von Benchmark auslösen könnte, eine eigene exception definieren soll?
Schau dir deinen Code an, schau dir meinen Code an. Mein Exception-Handling ist übersichtlicher und kann mehr. Es kann sogar Exceptions abfangen, die es nicht kennt (durch die Oberkategorie BenchmarkException).XtraNine hat geschrieben:Was ist den Pythonischer?
Stimmt, interne Funktionen und Variablen sind mit Unterstrich, "Daten" ohne. Aber da deine Klassen eigentlich nur "Daten" haben, macht das imho keinen Sinn (schwer zu beschreiben, aber einfach mal alles mit Unterstrich zu beginnen scheint mir schlicht umpythonisch, unter anderem weil dadurch nur unschöne Variablennamen rauskommen, ohne sonderlich überzeugenden Sinn).XtraNine hat geschrieben:Ich habe gelesen und auch BlackJack (in Pythons OOP erklärt) hat gesagt das man alle Methoden und alle Attribute die nicht Public sind, mit einen unterstrich am anfange definiert.
Das liegt in deinem Ermessen, du kannst es so oder so machen. Ich persönlich halte von sowas eigentlich nicht viel, weil mich die ganze Problematik (und Dogmatik) mit dem Private/Public total kalt lässt. Kann ich dir jetzt wirklich schwer erklären, bei mir ist es eben Einstellungssache. YMMV. Ich meine, wenn der Programmierer in der Klasse rumfischen will, ok, wenns auseinanderfällt ist er selbst schuld.XtraNine hat geschrieben:Das finde ich sinnvoll weil keiner diese Sachen anfassen soll und ich die auch nicht dokumentieren werde, wie es schon in PEP8 vorgeschlagen wird. Also self._functions, self._data, self._refTime sind für Interna bestimmt (also private) und sollen von außen _nicht_ angerührt werden. Falls ich damit falsch liege und es nicht so ist dann bitte berichtigen.
Exakt.XtraNine hat geschrieben:Nicht PEP8 kompatibel Wegen den Leerzeichen? Sollte es so aussehen?:Code: Alles auswählen
self._functions.append([ref.__name__, comment, ref, args])
Klar, ist gut.XtraNine hat geschrieben:Ok werde ich ändern, aber nicht als Dict mit listen drin, sonder als List mit Dicts drin, Weil...Dan kann man leicht darüber iterieren und braucht dann nur mit den Keys darauf zurückgreifen.Code: Alles auswählen
bench = Benchmark() [...] bench[0]['time'] # Laufzeit von Funktion 1. bench[1]['time'] # Laufzeit von Funktion 2, etc. [...]
Nein, ist es nicht. Man macht einfach eine Variable first, tail = data[0], data[1:] und arbeitet dann mit diesen Variablen weiter. Das ist schon wesentlich übersichlicher als [0][0]-Konstrukte.XtraNine hat geschrieben:Das sieht übersichtlicher bzw. ist einfacher als Zeile 296:
Welche? Die hier? Habe ich hiermit alsoXtraNine hat geschrieben:Aber wenn du Zeit hast könntest du ja die von mir kommentierten Sachen beantworten, weil ich mir da nicht sicher bin ob ich richtig liege.
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 => [[], [], []]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?
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)
)
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!"
)
Code: Alles auswählen
a = 0
bench = Benchmark()
bench.add_function(a, "LC", loops)
[…]
Code: Alles auswählen
self._functions.append([ref.__name__, comment, ref, args])
AttributeError: 'int' object has no attribute '__name__'
Code: Alles auswählen
if str(type(ref)) != "<type 'function'>":
raise WrongArgumentError("Das uebergeben Argument an ref ist "
"keine Referenz auf eine Funktion!")
Code: Alles auswählen
a = 0
bench = Benchmark()
bench.add_function(a, "LC", loops)
[…]
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!