Erfahren Sie, ob ein Objekt in Python ein Attribut hat

1635

Gibt es in Python eine Möglichkeit, festzustellen, ob ein Objekt ein Attribut hat? Zum Beispiel:

>>> a = SomeClass()
>>> a.someProperty = value
>>> a.property
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SomeClass instance has no attribute 'property'

Wie können Sie feststellen, ob adas Attribut vorhanden ist, propertybevor Sie es verwenden?

Lucas Gabriel Sánchez
quelle

Antworten:

2341

Versuchen Sie hasattr():

if hasattr(a, 'property'):
    a.property

EDIT: Siehe die zweite Antwort von untenlinde unten, die gute Ratschläge gibt, wie man um Vergebung bittet! Ein sehr pythonischer Ansatz!

Die allgemeine Praxis in Python lautet: Wenn die Eigenschaft wahrscheinlich die meiste Zeit vorhanden ist, rufen Sie sie einfach auf und lassen Sie die Ausnahme entweder weitergeben oder fangen Sie sie mit einem try / exception-Block ab. Dies wird wahrscheinlich schneller sein als hasattr. Wenn die Eigenschaft wahrscheinlich die meiste Zeit nicht vorhanden ist oder Sie sich nicht sicher sind, ist die Verwendung hasattrwahrscheinlich schneller als das wiederholte Fallen in einen Ausnahmeblock.

Jarret Hardie
quelle
19
Scheint auch für die Suche nach Funktionen im Namespace zu arbeiten, zB: import string hasattr(string, "lower")
Riviera
15
hasattrist genau das gleiche wie die Verwendung von try/ except AttributeError: Die Dokumentzeichenfolge von hasattr (in Python 2.7) besagt, dass getattr verwendet wird. Hand fängt Ausnahmen ab.
Jeff Tratner
8
@ JeffTratner: hasattrist leider nicht genau das gleiche wie try: ... except AttributeError:in Python 2.x, da alle Ausnahmen abgefangen hasattrwerden . In meiner Antwort finden Sie ein Beispiel und eine einfache Problemumgehung.
Martin Geisler
632

Wie Jarret Hardie antwortete, hasattrwird er den Trick machen. Ich möchte jedoch hinzufügen, dass viele in der Python-Community eine Strategie empfehlen, bei der es einfacher ist, um Vergebung zu bitten als um Erlaubnis (EAFP), anstatt "schauen, bevor Sie springen" (LBYL). Siehe diese Referenzen:

EAFP gegen LBYL (war Re: Bisher ein wenig enttäuscht)
EAFP gegen LBYL @Code Wie ein Pythonista: Idiomatisches Python

dh:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

... wird bevorzugt gegenüber:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()
fällinde
quelle
257
Aber wie überprüfen Sie, ob es die Eigenschaft a. war, die AttributeError verursacht hat, und nicht etwas in doStuff ()? Es scheint, dass Sie nicht. Ich denke, es ist wirklich einfacher, um Vergebung zu bitten, aber oft ist es auch falsch.
Jpalecek
283
EAFP scheint ... verrückt zu sein. HasAttr telegraphiert an zukünftige Wartungsprogrammierer, die Sie auf ein bestimmtes Attribut prüfen. Eine Ausnahme zu bekommen, sagt zukünftigen Programmierern nichts und könnte jemanden in den Kaninchenbau führen.
Ethan Heilman
74
@ e5: Sie haben in diesem Fall einen fairen Punkt, aber in vielen Fällen ist EAFP die einzig richtige Option. Wenn Sie beispielsweise die Existenz einer Datei überprüfen und sie dann öffnen und erwarten, dass sie definitiv vorhanden ist, ist Ihr Code falsch: Die Datei wird möglicherweise zwischen der Prüfung und der Verwendung gelöscht oder umbenannt. Dies wird als TOCTOU-Fehler (Time-Of-Check-To-Time-Of-Use) bezeichnet und kann neben Abstürzen auch Sicherheitslücken verursachen.
Max
15
@EthanHeilman Es ist nur verrückt, wenn die Quelle der Ausnahme mehrdeutig ist, was in den meisten Fällen mit gutem Design vermieden werden kann. Eine gut geschichtete Strukturierung der Logik innerhalb von try / exception / finally führt im Allgemeinen zu einer robusteren (weniger programmiererfehleranfälligen) Logik, als den Code mit präventiven if-Checks für jeden verbrauchenden Code zu übersäen. Macht Fehler auch sehr deutlich und ermöglicht es konsumierenden Programmierern, direkt mit ihnen umzugehen.
Peter M. Elias
64
Die meisten Mehrdeutigkeitsbeschwerden sind einfach darauf zurückzuführen, dass der Beispielcode schlecht strukturiert ist. Das einzige, was darin enthalten sein try:sollte, ist der versuchte Attributzugriff. Es gibt keinen Grund, die Ausführung ebenfalls zu beenden doStuff. Es besteht jedoch immer noch ein gewisses Potenzial für Mehrdeutigkeiten: Wenn propertyes sich um eine berechnete Eigenschaft anstelle eines einfachen Attributs handelt, kann sich die Implementierung AttributeErrorintern erhöhen . Aus diesem Grund ist es in fast allen realen Situationen wie diesen getattrentweder vorzuziehen hasattroder zu fangen AttributeError.
Carl Meyer
485

Sie können verwenden hasattr()oder abfangen AttributeError, aber wenn Sie wirklich nur den Wert des Attributs mit einem Standardwert möchten, wenn er nicht vorhanden ist, ist die beste Option, einfach Folgendes zu verwenden getattr():

getattr(a, 'property', 'default value')
Carl Meyer
quelle
14
Dies löst beide oben genannten Probleme: a) Die Mehrdeutigkeit der Quelle eines möglichen AttributeError, b) Beibehaltung des EAFP-Ansatzes.
Peter M. Elias
6
Es sind auch 25% der Codezeilen. Dies muss sicherlich die beste Lösung sein.
Fatuhoku
16
Dies ist die beste Lösung, "wenn Sie wirklich nur den Wert des Attributs mit einem Standardwert möchten". Obwohl ich glaube, dass dies das ist, was viele Leute tatsächlich wollen, wenn sie sagen, dass sie erkennen wollen, ob ein Attribut vorhanden ist, hat das OP tatsächlich nach letzterem gefragt, so dass es vernünftig ist, die direkten Antworten auf diese Frage (hasattr, AttributeError) höher aufzulisten .
Carl Meyer
41

Ich denke, was Sie suchen, ist hasattr . Ich würde jedoch so etwas empfehlen, wenn Sie Python-Eigenschaften erkennen möchten -

try:
    getattr(someObject, 'someProperty')         
except AttributeError:
    print "Doesn't exist"
else
    print "Exists"

Der Nachteil hierbei ist, dass auch Attributfehler im Eigenschaftencode __get__abgefangen werden.

Andernfalls tun Sie

if hasattr(someObject, 'someProp'):
    #Access someProp/ set someProp
    pass

Docs: http://docs.python.org/library/functions.html
Warnung:
Der Grund für meine Empfehlung ist, dass hasattr keine Eigenschaften erkennt.
Link: http://mail.python.org/pipermail/python-dev/2005-December/058498.html

Batbrat
quelle
3
hasattrerkennt Eigenschaften im Allgemeinen gut. Es ist nur so, dass das propertyAuslösen einer Ausnahme in der Funktion -wrapped so behandelt wird, dass kein solches Attribut vorhanden ist. Der verknüpfte Python-Mailinglistenbeitrag handelt von einer Eigenschaft, die eine Ausnahme auslöst, wenn Sie versuchen, darauf zuzugreifen. Für alle praktischen Zwecke existiert dieses Attribut nicht, da es niemals einen Wert erzeugen wird. hasattrUnterdrückt außerdem nur Ausnahmen im Allgemeinen in Py 3.1 und früheren Versionen. in 3.2+ wird nur unterdrückt (durch Falsereturn ersetzt) AttributeError.
ShadowRanger
32

Laut pydoc ruft hasattr (obj, prop) einfach getattr (obj, prop) auf und fängt Ausnahmen ab. Es ist also genauso gültig, den Attributzugriff mit einer try-Anweisung zu versehen und AttributeError abzufangen, wie zuvor hasattr () zu verwenden.

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value
Jordan Lewis
quelle
2
Nun, Hasattr kann tatsächlich optimiert werden. ZB mit Pypy.
Odinho - Velmont
6
+1. Dies ist sogar sicherer als die Verwendung hasattrbei den SomeClassÜberschreibungen __getattr__seit hasattrwerden fangen alle Ausnahmen in Python 2.x, nicht nur AttributeErrorwie man erwarten würde. Dies wurde in Python 3.2 behoben. Eine einfache Problemumgehung finden Sie in meiner anderen Antwort .
Martin Geisler
24

Ich möchte vorschlagen, dies zu vermeiden:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

Der Benutzer @jpalecek erwähnte es: Wenn ein AttributeErrordrinnen auftritt doStuff(), sind Sie verloren.

Vielleicht ist dieser Ansatz besser:

try:
    val = a.property
except AttributeError:
    otherStuff()
else:
    doStuff(val)
Maico
quelle
13

Je nach Situation können Sie überprüfen, isinstancewelche Art von Objekt Sie haben, und dann die entsprechenden Attribute verwenden. Mit der Einführung abstrakter Basisklassen in Python 2.6 / 3.0 ist dieser Ansatz auch viel leistungsfähiger geworden (ABCs ermöglichen im Grunde eine ausgefeiltere Art der Ententypisierung).

Eine Situation, in der dies nützlich ist, wäre, wenn zwei verschiedene Objekte ein Attribut mit demselben Namen, aber unterschiedlicher Bedeutung haben. Nur hasattrdie Verwendung kann dann zu seltsamen Fehlern führen.

Ein schönes Beispiel ist die Unterscheidung zwischen Iteratoren und Iterablen (siehe diese Frage). Die __iter__Methoden in einem Iterator und einem Iterator haben den gleichen Namen, sind aber semantisch sehr unterschiedlich! Ist hasattralso nutzlos, isinstancebietet aber zusammen mit ABC eine saubere Lösung.

Ich stimme jedoch zu, dass in den meisten Situationen der hasattrAnsatz (in anderen Antworten beschrieben) die am besten geeignete Lösung ist.

Nikow
quelle
13

Ich hoffe, Sie erwarten hasattr (), aber versuchen Sie, hasattr () zu vermeiden, und bevorzugen Sie bitte getattr (). getattr () ist schneller als hasattr ()

mit hasattr ():

 if hasattr(a, 'property'):
     print a.property

das gleiche hier verwende ich getattr, um Eigenschaft zu erhalten, wenn es keine Eigenschaft gibt, gibt es keine zurück

   property = getattr(a,"property",None)
    if property:
        print property
Janarthanan Ramu
quelle
11

EDIT : Dieser Ansatz hat ernsthafte Einschränkungen. Es sollte funktionieren, wenn das Objekt iterierbar ist . Bitte überprüfen Sie die Kommentare unten.

Wenn Sie Python 3.6 oder höher wie ich verwenden, gibt es eine bequeme Alternative, um zu überprüfen, ob ein Objekt ein bestimmtes Attribut hat:

if 'attr1' in obj1:
    print("attr1 = {}".format(obj1["attr1"]))

Ich bin mir jedoch nicht sicher, welcher Ansatz derzeit der beste ist. Verwenden hasattr(), Verwenden getattr()oder Verwenden in. Kommentare sind willkommen.

Nayak
quelle
6
inDas Schlüsselwort dient zum Überprüfen iterierbarer Typen. Zum Beispiel 'foo' in Nonelöst der Fehler aus TypeError: argument of type 'NoneType' is not iterable. Das Update besteht darin, vor der Verwendung zu überprüfen, ob der Typ iterierbar ist in. Nachdem Sie Kantenfälle wie nicht iterierbare Typen korrigiert haben, ist es wahrscheinlich besser, sie zu verwenden, hasattr()da sie für die Behandlung von Randfällen ausgelegt sind.
Seth Difley
3
Dies hat nichts mit Attributzugriff zu tun. Ich habe keine Ahnung, wie es positiv bewertet wurde. Die einzige Ähnlichkeit, die der Attributzugriff aufweisen muss, besteht darin, dass Sie ihn dictals "leichtgewichtiges Objekt" verwenden, ähnlich wie beim Entwurf von JavaScript-Objekten. Die meisten normalen Klassen unterstützen dies jedoch im Allgemeinen nicht (eine Variante des von @SethDifley erwähnten Fehlers wird abgerufen). .
ShadowRanger
6

Hier ist ein sehr intuitiver Ansatz:

if 'property' in dir(a):
    a.property
Alec Alameddine
quelle
1

Dies ist sehr einfach. Verwenden Sie einfach das dir(Objekt.)
Dies gibt eine Liste aller verfügbaren Funktionen und Attribute des Objekts zurück.

Sean Christen
quelle
1

Eine andere mögliche Option, aber es hängt davon ab, was Sie vorher damit meinen :

undefined = object()

class Widget:

    def __init__(self):
        self.bar = 1

    def zoom(self):
        print("zoom!")

a = Widget()

bar = getattr(a, "bar", undefined)
if bar is not undefined:
    print("bar:%s" % (bar))

foo = getattr(a, "foo", undefined)
if foo is not undefined:
    print("foo:%s" % (foo))

zoom = getattr(a, "zoom", undefined)
if zoom is not undefined:
    zoom()

Ausgabe:

bar:1
zoom!

Auf diese Weise können Sie sogar nach Attributen ohne Wert suchen.

Aber! Seien Sie sehr vorsichtig, dass Sie nicht versehentlich undefinedmehrere Orte instanziieren und vergleichen, da dies isin diesem Fall niemals funktioniert.

Aktualisieren:

Aufgrund dessen, worüber ich im obigen Absatz gewarnt habe, da mehrere undefinierte Werte nie übereinstimmen, habe ich dieses Muster kürzlich geringfügig geändert:

undefined = NotImplemented

NotImplemented, nicht zu verwechseln NotImplementedError, ist ein integriertes Element: Es entspricht halb der Absicht eines JS, undefinedund Sie können seine Definition überall wiederverwenden, und es stimmt immer überein. Die Nachteile sind, dass es in Booleschen Werten "wahr" ist und in Protokollen und Stapelspuren seltsam aussehen kann (aber Sie kommen schnell darüber hinweg, wenn Sie wissen, dass es nur in diesem Kontext erscheint).

JL Peyret
quelle
0

Sie können objectmithilfe der hasattrintegrierten Methode überprüfen, ob Attribute enthalten sind.

Für eine Instanz, wenn Ihr Objekt ist aund Sie nach Attributen suchen möchtenstuff

>>> class a:
...     stuff = "something"
... 
>>> hasattr(a,'stuff')
True
>>> hasattr(a,'other_stuff')
False

Die Methodensignatur selbst hasattr(object, name) -> boolbedeutet, dass objectdas Attribut, das an das zweite Argument übergeben hasattrwird, boolesch ist Trueoder Falsedem Vorhandensein eines nameAttributs im Objekt entspricht.

Devang Padhiyar
quelle
0

hasattr()ist die richtige Antwort. Was ich hinzufügen möchte, ist, dass hasattr()es auch gut in Verbindung mit assert verwendet werden kann (um unnötige ifAnweisungen zu vermeiden und den Code lesbarer zu machen):

assert hasattr(a, 'property'), 'object lacks property' 

Wie in einer anderen Antwort zu SO angegeben : Asserts sollten verwendet werden, um Bedingungen zu testen, die niemals eintreten sollten. Der Zweck besteht darin, bei einem beschädigten Programmstatus frühzeitig abzustürzen.

FMF
quelle
Dies ist hilfreich, aber möglicherweise nicht immer der Fall. Vielleicht wollte ich testen, ob das Objekt eine Eigenschaft hat, und es dann zum ersten Mal hinzufügen, oder ich muss anderen Code für Objekte mit dieser Eigenschaft ausführen. Wenn der Code nicht fortgesetzt werden kann, ist die Bestätigung möglicherweise in Ordnung. Aber auch dies ist nicht immer der Fall. Wichtig ist, dass hasattrnicht der umgebende Code verwendet wird.
Lucas Gabriel Sánchez