if hasattr(obj, 'attribute'):
# do somthing
gegen
try:
# access obj.attribute
except AttributeError, e:
# deal with AttributeError
Welche sollte bevorzugt werden und warum?
if hasattr(obj, 'attribute'):
# do somthing
gegen
try:
# access obj.attribute
except AttributeError, e:
# deal with AttributeError
Welche sollte bevorzugt werden und warum?
Gibt es Bänke, die den Leistungsunterschied verdeutlichen?
timeit ist dein Freund
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'hasattr(c, "nonexistent")'
1000000 loops, best of 3: 1.87 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'hasattr(c, "a")'
1000000 loops, best of 3: 0.446 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'try:
c.a
except:
pass'
1000000 loops, best of 3: 0.247 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'try:
c.nonexistent
except:
pass'
100000 loops, best of 3: 3.13 usec per loop
$
|positive|negative
hasattr| 0.446 | 1.87
try | 0.247 | 3.13
+1 für die Bereitstellung interessanter, greifbarer Zahlen. Der "try" ist in der Tat effizient, wenn er den Normalfall enthält (d. h. wenn eine Python-Ausnahme wirklich außergewöhnlich ist).
Ich bin mir nicht sicher, wie diese Ergebnisse zu interpretieren sind. Was ist hier schneller, und um wie viel?
@StevenM.Vascellaro: Wenn das Attribut existiert, try
ist etwa doppelt so schnell wie hasattr()
. Wenn das nicht der Fall ist, try
ist etwa 1,5x langsamer als hasattr()
(und beide sind wesentlich langsamer, als wenn das Attribut vorhanden ist). Dies liegt wahrscheinlich daran, dass auf dem glücklichen Weg, try
tut kaum etwas (Python zahlt bereits für den Overhead der Ausnahmen, unabhängig davon, ob Sie sie verwenden), aber hasattr()
erfordert eine Namenssuche und einen Funktionsaufruf. Auf dem unglücklichen Pfad müssen sie beide eine Ausnahmebehandlung und einen goto
mais hasattr()
macht es in C und nicht in Python-Bytecode.
Außer, dass Sie noch den try/catch-Block benötigen, um Race Conditions zu behandeln (wenn Sie Threads verwenden).
Oder der spezielle Fall, auf den ich gerade gestoßen bin: ein django OneToOneField ohne Wert: hasattr(obj, field_name) gibt False zurück, aber es gibt ein Attribut mit field_name: es wird einfach ein DoesNotExist-Fehler ausgegeben.
Beachten Sie, dass hasattr
wird alle Ausnahmen auffangen in Python 2.x. Siehe meine Antwort für ein Beispiel und die triviale Umgehung.
Es gibt eine dritte und oft bessere Alternative:
attr = getattr(obj, 'attribute', None)
if attr is not None:
print attr
Vorteile:
getattr
hat nicht die schlechte das von Martin Geiser aufgezeigte Verhalten beim Schlucken von Ausnahmen - in alten Pythons, hasattr
verschluckt sogar eine KeyboardInterrupt
.
Der normale Grund, warum Sie prüfen, ob das Objekt ein Attribut hat, ist, dass Sie das Attribut verwenden können, und das führt natürlich dazu.
Das Attribut wird atomar ausgelesen und ist vor anderen Threads, die das Objekt verändern, sicher. (Wenn dies jedoch ein wichtiges Anliegen ist, sollten Sie erwägen, das Objekt zu sperren, bevor Sie darauf zugreifen).
Es ist kürzer als try/finally
und oft kürzer als hasattr
.
Eine breite except AttributeError
Block kann andere AttributeErrors
als der, den Sie erwarten, was zu verwirrendem Verhalten führen kann.
Der Zugriff auf ein Attribut ist langsamer als der Zugriff auf eine lokale Variable (insbesondere wenn es sich nicht um ein einfaches Instanzattribut handelt). (Obwohl, um ehrlich zu sein, Mikro-Optimierung in Python ist oft ein Narr's Errand).
Eine Sache, auf die Sie achten sollten, ist, wenn Sie sich für den Fall interessieren, dass obj.attribute
auf None gesetzt ist, müssen Sie einen anderen Sentinel-Wert verwenden.
+1 - Dies steht in einer Reihe mit dict.get('my_key', 'default_value') und sollte besser bekannt sein
Ideal für häufige Anwendungsfälle, in denen Sie das Vorhandensein prüfen und das Attribut mit Standardwert verwenden möchten.
Ich verwende fast immer hasattr
: In den meisten Fällen ist es die richtige Wahl.
Problematisch ist der Fall, dass eine Klasse die __getattr__
: hasattr
wird alle Ausnahmen auffangen statt nur zu fangen AttributeError
wie Sie es erwarten. Mit anderen Worten, der folgende Code druckt b: False
auch wenn es angemessener wäre, eine ValueError
Ausnahme:
class X(object):
def __getattr__(self, attr):
if attr == 'a':
return 123
if attr == 'b':
raise ValueError('important error from your database')
raise AttributeError
x = X()
print 'a:', hasattr(x, 'a')
print 'b:', hasattr(x, 'b')
print 'c:', hasattr(x, 'c')
Der wichtige Fehler ist damit verschwunden. Dies war behoben in Python 3.2 ( Ausgabe9666 ) wobei hasattr
fängt jetzt nur noch AttributeError
.
Eine einfache Abhilfe besteht darin, eine Dienstprogrammfunktion wie die folgende zu schreiben:
_notset = object()
def safehasattr(thing, attr):
return getattr(thing, attr, _notset) is not _notset
Das lässt getattr
mit der Situation umgehen und kann dann die entsprechende Ausnahme auslösen.
Dies war auch ein wenig verbessert in Python2.6, so dass hasattr
wird zumindest nicht erwischt KeyboardInterrupt
usw.
Oder, stattdessen safehasattr
verwenden Sie einfach getattr
um den Wert in eine lokale Variable zu kopieren, wenn Sie ihn verwenden wollen, was fast immer der Fall ist.
@poolie Das ist schön, das wusste ich nicht hasattr
auf diese Weise verbessert worden war.
Ich würde sagen, es hängt davon ab, ob Ihre Funktion Objekte ohne das Attribut akzeptieren kann konstruktionsbedingt z.B. wenn Sie zwei Aufrufer der Funktion haben, von denen einer ein Objekt mit dem Attribut und der andere ein Objekt ohne dieses Attribut liefert.
Wenn der einzige Fall, in dem Sie ein Objekt ohne das Attribut erhalten, auf einen Fehler zurückzuführen ist, würde ich empfehlen, den Ausnahmemechanismus zu verwenden, auch wenn er langsamer sein kann, weil ich glaube, dass es ein saubereres Design ist.
Unterm Strich: Ich denke, es ist eher ein Problem des Designs und der Lesbarkeit als ein Problem der Effizienz.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
1 Stimmen
Duplikat: stackoverflow.com/questions/598157/ , stackoverflow.com/questions/610883/