if hasattr(obj, 'attribute'):
# do somthing
vs.
try:
# access obj.attribute
except AttributeError, e:
# deal with AttributeError
Welches sollte bevorzugt werden und warum?
if hasattr(obj, 'attribute'):
# do somthing
vs.
try:
# access obj.attribute
except AttributeError, e:
# deal with AttributeError
Welches sollte bevorzugt werden und warum?
Antworten:
hasattr
führt intern und schnell dieselbe Aufgabe wie dertry/except
Block aus: Es ist ein sehr spezifisches, optimiertes Tool für eine Aufgabe und sollte daher gegebenenfalls der sehr universellen Alternative vorgezogen werden.quelle
hasattr
werden alle Ausnahmen fangen in Python 2.x. In meiner Antwort finden Sie ein Beispiel und die einfache Problemumgehung.try
kann vermitteln, dass die Operation funktionieren sollte . Obwohltry
die Absicht nicht immer so ist, ist sie üblich, so dass sie als besser lesbar angesehen werden kann.Gibt es Bänke, die Leistungsunterschiede veranschaulichen?
Timeit, es ist dein Freund
quelle
try
ist es ungefähr doppelt so schnell wiehasattr()
. Wenn dies nicht der Fall ist,try
ist es ungefähr 1,5x langsamer alshasattr()
(und beide sind wesentlich langsamer als wenn das Attribut vorhanden ist). Dies liegt wahrscheinlich daran, dass auf dem glücklichen Pfadtry
kaum etwas unternommen wird (Python zahlt bereits für den Overhead von Ausnahmen, unabhängig davon, ob Sie sie verwenden),hasattr()
erfordert jedoch eine Namenssuche und einen Funktionsaufruf. Auf dem unglücklichen Pfad müssen beide eine Ausnahmebehandlung und a ausführengoto
,hasattr()
dies jedoch in C und nicht in Python-Bytecode.Es gibt eine dritte und oft bessere Alternative:
Vorteile:
getattr
hat nicht das schlechte Ausnahme-Schluckverhalten, auf das Martin Geiser hingewiesen hat - in alten Pythonshasattr
wird sogar ein schluckenKeyboardInterrupt
.Der normale Grund, warum Sie prüfen, ob das Objekt ein Attribut hat, besteht darin, dass Sie das Attribut verwenden können, und dies führt natürlich dazu.
Das Attribut wird atomar abgelesen und ist vor anderen Threads geschützt, die das Objekt ändern. (Wenn dies jedoch ein wichtiges Anliegen ist, sollten Sie das Objekt vor dem Zugriff sperren.)
Es ist kürzer als
try/finally
und oft kürzer alshasattr
.Ein breiter
except AttributeError
Block kann andereAttributeErrors
als den von Ihnen erwarteten fangen , 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). (Um ehrlich zu sein, ist die Mikrooptimierung in Python oft ein Kinderspiel.)
Wenn Sie sich für den Fall interessieren
obj.attribute
, in dem Keine festgelegt ist, müssen Sie einen anderen Sentinel-Wert verwenden.quelle
Ich benutze fast immer
hasattr
: Es ist in den meisten Fällen die richtige Wahl.Der problematische Fall ist , wenn eine Klasse überschreibt
__getattr__
:hasattr
werden alle Ausnahmen fangen , anstatt nur zu fangen ,AttributeError
wie Sie es erwarten. Mit anderen Worten, der folgende Code wird gedrucktb: False
, obwohl es angemessener wäre, eineValueError
Ausnahme zu sehen :Der wichtige Fehler ist damit verschwunden. Dies wurde in Python 3.2 ( Problem 9666 ) behoben, wo
hasattr
jetzt nur noch Fänge auftretenAttributeError
.Eine einfache Problemumgehung besteht darin, eine Dienstprogrammfunktion wie die folgende zu schreiben:
Lassen Sie uns
getattr
die Situation behandeln und dann die entsprechende Ausnahme auslösen.quelle
hasattr
zumindest nicht fangenKeyboardInterrupt
usw.safehasattr
einfachgetattr
in eine lokale Variable, wenn Sie ihn verwenden möchten, was Sie fast immer sind.hasattr
das so verbessert wurde.hasattr
, und ging, um nachzusehen. Wir hatten einige lustige BZR-Bugs, bei denen Hasattr gerade geschluckt hat ^ C.Ich würde sagen, es hängt davon ab, ob Ihre Funktion Objekte ohne das Attribut beabsichtigt , z. B. wenn Sie zwei Aufrufer für die Funktion haben, von denen einer ein Objekt mit dem Attribut und der andere ein Objekt ohne das Attribut bereitstellt.
Wenn der einzige Fall, in dem Sie ein Objekt ohne das Attribut erhalten, auf einen Fehler zurückzuführen ist, würde ich die Verwendung des Ausnahmemechanismus empfehlen, auch wenn dieser möglicherweise langsamer ist, da ich glaube, dass es sich um ein saubereres Design handelt.
Fazit: Ich denke, es ist eher ein Design- und Lesbarkeitsproblem als ein Effizienzproblem.
quelle
Wenn das Fehlen des Attributs keine Fehlerbedingung ist, hat die Ausnahmebehandlungsvariante ein Problem: Sie fängt auch AttributeErrors ab, die möglicherweise intern beim Zugriff auf obj.attribute auftreten (z. B. weil attribute eine Eigenschaft ist, sodass beim Zugriff darauf Code aufgerufen wird).
quelle
Wenn es nur ein Attribut ist, das Sie testen, würde ich verwenden verwenden
hasattr
. Wenn Sie jedoch mehrere Zugriffe auf Attribute ausführen, die möglicherweise vorhanden sind oder nicht,try
erspart Ihnen die Verwendung eines Blocks möglicherweise einige Eingaben.quelle
Ich würde Option 2 vorschlagen. Option 1 hat eine Race-Bedingung, wenn ein anderer Thread das Attribut hinzufügt oder entfernt.
Auch Python hat eine Redewendung , dass EAFP ("leichter um Vergebung als um Erlaubnis zu bitten") besser ist als LBYL ("schau bevor du springst").
quelle
Dieses Thema wurde im EuroPython 2016-Vortrag „ Schnelleres Python schreiben“ von Sebastian Witowski behandelt. Hier ist eine Reproduktion seiner Folie mit der Leistungsübersicht. Er verwendet auch den Terminologie- Look, bevor Sie in diese Diskussion einsteigen. Erwähnenswert ist hier, um dieses Schlüsselwort zu kennzeichnen.
3 ERLAUBNISSE ODER VERGEBUNG?
quelle
Aus praktischer Sicht ist die Verwendung einer Bedingung in den meisten Sprachen immer wesentlich schneller als die Behandlung einer Ausnahme.
Wenn Sie den Fall eines Attributs behandeln möchten, das nicht außerhalb der aktuellen Funktion vorhanden ist, ist die Ausnahme der bessere Weg. Ein Indikator dafür, dass Sie möglicherweise eine Ausnahme anstelle einer Bedingung verwenden möchten, ist, dass die Bedingung lediglich ein Flag setzt und die aktuelle Operation abbricht. An anderer Stelle wird dieses Flag überprüft und basierend darauf Maßnahmen ergriffen.
Wie Rax Olgud betont, ist die Kommunikation mit anderen ein wichtiges Attribut des Codes, und was Sie sagen möchten, indem Sie sagen, dass dies eine Ausnahmesituation ist und nicht, dass dies etwas ist, von dem ich erwarte, dass es passiert, ist möglicherweise wichtiger .
quelle
Der Erste.
Kürzer ist besser. Ausnahmen sollten außergewöhnlich sein.
quelle
for
Anweisung undhasattr
verwendet auch eine. Es gilt jedoch "kürzer ist besser" (und "einfacher ist besser"!). Daher ist das einfachere, kürzere und spezifischere Hasattr in der Tat vorzuziehen.Zumindest, wenn es nur darum geht, was im Programm vor sich geht, den menschlichen Teil der Lesbarkeit usw. wegzulassen (was eigentlich meistens wichtiger ist als die Leistung (zumindest in diesem Fall - mit dieser Leistungsspanne)). wie Roee Adler und andere betonten).
Wenn man es jedoch aus dieser Perspektive betrachtet, ist es dann eine Frage der Wahl zwischen
und
da verwendet
hasattr
nur den ersten Fall, um das Ergebnis zu bestimmen. Denkanstöße ;-)quelle