[Python-de] auf Liste testen
Ulrich Berning
ulrich.berning at desys.de
Fre Dez 16 11:51:17 CET 2005
Diez B. Roggisch schrieb:
>On Thursday 15 December 2005 15:12, Andreas Jung wrote:
>
>
>>--On 15. Dezember 2005 15:01:47 +0100 Jochen Schulz <ml at well-adjusted.de>
>>
>>wrote:
>>
>>
>>>Aber willst Du das wirklich? In Python versucht man meist gerade keinen
>>>bestimmten Typ vorzuschreiben, sondern probiert einfach die Operationen
>>>auf dem Objekt, die man machen will.
>>>
>>>
>>Wer hat Dir denn diesen Blödsinn beigebracht? Bis Du PHP/Perl
>>Programmierer? :-)
>>
>>
>
>So einen Bloedsinn verzapft uA Alex Martelli, Autor des Cookbooks und sicher
>einer der profiliertesten Python-Coder weltweit:
>
>http://groups.google.com/group/comp.lang.python/browse_frm/thread/82b36a09772bb37/e230ca916be58835?lnk=st&q=martelli+duck+typing+python&rnum=6&hl=en#e230ca916be58835
>
>
>
Duck-Typing bedeutet keinesfalls, dass man einfach Operationen auf einem
Objekt ausfuehrt, ohne zu pruefen, ob das Objekt diese Operationen auch
zur Verfuegung stellt. Duck-Typing bedeutet lediglich, dass man nicht
den Typ eines Objektes erfragt, um vom Typ des Objektes auf die
implementierte Schnittstelle zu schliessen, sondern man prueft
stattdessen, ob das Objekt die benoetigte Schnittstelle implementiert.
Die Betonung liegt auf pruefen.
Eine Operation einfach zu probieren und eventuelle Fehler abzufangen
wuerde ich eher Try-And-Error nennen und hat mit Duck-Typing nicht viel
zu tun.
Zitat:
"In other words, don't check whether it IS-a duck: check whether it
QUACKS-like-a duck, WALKS-like-a duck, etc, etc, depending on exactly
what subset of duck-like behaviour you need to play your language-games
with."
Allen, die vor der Ausfuehrung von Operationen nicht pruefen wollen
(egal ob Typ oder Schnittstelle), sondern lieber die Operation einfach
ausfuehren und den Fehlerfall mit try/except fangen, moechte ich das
angehaengte Script nahelegen. Mal abgesehen davon, dass ich
Try-And-Error fuer ganz schlechten Stil halte und es der Lesbarkeit
nicht gerade zutraeglich ist, hat das Vefahren auch erhebliche
Auswirkungen auf die Performance.
Ich halte mich an folgende Regeln:
1.) Ich verwende type() wenn moeglich oder zwingend notwendig.
2.) Ich verwende isinstance() wenn type() nicht geht (wg. Ableitungen).
3.) Duck-Typing kommt nur dann zur Anwendung, wenn ich vom Typ eines
Objektes nicht auf seine implemetierte Schnittstelle schliessen kann, z.
B. wenn die Schnittstelle eines Objektes zur Laufzeit erzeugt oder
veraendert wird.
4.) Try-And-Error vermeide ich moeglichst immer.
---
Ulli
-------------- nächster Teil --------------
import time
# Diese Konvertierungs-Funktion verwendet type(),
# um den Typ des Objektes zu erfragen. Das ist nur
# dann brauchbar, wenn ich nicht mit Ableitungen
# des Typs rechnen muss.
def f1(obj):
if type(obj) == str:
return obj.lower()
elif type(obj) == int:
return hex(obj)
elif type(obj) == float:
return abs(obj)
return obj
# Diese Konvertierungs-Funktion verwendet isinstance(),
# um den Typ des Objektes zu erfragen. Das funktioniert
# auch bei Ableitungen des Typs.
def f2(obj):
if isinstance(obj, str):
return obj.lower()
elif isinstance(obj, int):
return hex(obj)
elif isinstance(obj, float):
return abs(obj)
return obj
# Dies ist Duck-Typing. Anstatt den Typ des Objektes zu
# erfragen und vom Typ des Objektes auf die implemetierte
# Schnittstelle zu schliessen, wird die Schnittstelle
# des Objektes erfragt. Man kann schon erkennen, dass das
# aufgrund der unten definierten Regeln problematisch werden
# kann.
def f3(obj):
if hasattr(obj, 'lower'):
return obj.lower()
elif hasattr(obj, '__hex__'):
return hex(obj)
elif hasattr(obj, '__abs__'):
return abs(obj)
return obj
# Dies ist Try-And-Error. Wir versuchen einfach die
# Operation auszufuehren und fangen auftretende Fehler ab.
def f4(obj):
try:
return obj.lower()
except (AttributeError, TypeError):
pass
try:
return hex(obj)
except (AttributeError, TypeError):
pass
try:
return abs(obj)
except (AttributeError, TypeError):
pass
return obj
#
# Main
#
if __name__ == '__main__':
records = ((("A", "B", "C", 1, 2, 3, 0.1, 0.2, -0.3, None,
"D", "E", "F", 4, 5, 6, 0.4, 0.5, -0.6, None),)*100000)
print "Verarbeite %d Datensaetze mit %d Spalten..." % (len(records), len(records[0]))
print
print "Regeln:"
print "1.) Alle Strings in Kleinbuchstaben konvertieren."
print "2.) Alle Integers in Hex-Strings konvertieren."
print "3.) Von allen Floats wird der Absolutwert gebildet."
print "4.) Alle anderen Typen bleiben unmodifiziert."
print
start_time = time.time()
for record in records:
for column in record:
f1(column)
print "%.3f Sek. mit type()" % (time.time() - start_time)
start_time = time.time()
for record in records:
for column in record:
f2(column)
print "%.3f Sek. mit isinstance()" % (time.time() - start_time)
start_time = time.time()
for record in records:
for column in record:
f3(column)
print "%.3f Sek. mit hasattr()" % (time.time() - start_time)
start_time = time.time()
for record in records:
for column in record:
f4(column)
print "%.3f Sek. mit try/except" % (time.time() - start_time)