Wie liste ich die Eigenschaften eines Objekts in Python auf?

133

IC # wir machen es durch Reflexion. In Javascript ist es einfach wie:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

Wie geht das in Python?

Jader Dias
quelle
3
Bitte beachten Sie, dass diese Frage eine falsche Bezeichnung ist. Bei den meisten Antworten geht es um die Aufzählung von Mitgliedern . Ich suchte nach einer Möglichkeit, Eigenschaften aufzuzählen , dh Mitglieder einer Klasse, die mit dekoriert ist @property.
Tomasz Gandor

Antworten:

153
for property, value in vars(theObject).iteritems():
    print property, ": ", value

Beachten Sie, dass es in einigen seltenen Fällen eine __slots__Eigenschaft gibt, solche Klassen haben oft keine __dict__.

Georg Schölly
quelle
1
Wie kann man nun den Wert ändern? In Javascript können Sie Folgendes tun: object [property] = newValue. Wie geht das in Python?
Jader Dias
39
Verwenden Sie stattdessen setattr ().
Nelson
1
@ Nelson Könnten Sie näher erläutern, warum dies eine bessere Option ist? Ist es nur kürzer oder gibt es zusätzliche Überlegungen?
WhyNotHugo
8
@Hugo: Erstens, weil es "pythonisch" ist, mit anderen Worten, das ist die Syntax, die eine große Mehrheit der Community erwartet. Die andere Syntax würde wahrscheinlich jedem, der Ihren Code liest, unnötig eine Pause geben. Zweitens implementieren einige Typen einen Setter __setattr__(). Das Festlegen von Werten direkt im Wörterbuch umgeht den Setter des Objekts (und / oder dessen Eltern). In Python ist es durchaus üblich, dass während der Attributeinstellung (z. B. Hygiene) mehr Dinge im Hintergrund passieren setattr(), als Sie sich vorstellen können. Dadurch wird sichergestellt, dass Sie nichts verpassen oder gezwungen sind, diese explizit selbst zu behandeln.
Michael Ekoka
3
@ Hi-Angel Das funktioniert . Was jedoch nicht funktioniert, ist die Konstellation von Vorurteilen und Annahmen, die Sie in Python im Vergleich zu dynamischen Objektmitgliedern haben. vars()Gibt nur statische Elemente zurück (dh Objektattribute und Methoden, die bei diesem Objekt registriert sind __dict__). Es spielt keine Rück dynamischer Elemente (dh Objektattribute und Methoden dynamisch durch dieses Objekt definierte __getattr__()Methode oder ähnliche Magie). Höchstwahrscheinlich wird Ihre gewünschte file.ImplementationNameEigenschaft dynamisch definiert und steht daher oder nicht zur Verfügung . vars()dir()
Cecil Curry
69

Siehe inspect.getmembers(object[, predicate]).

Gibt alle Mitglieder eines Objekts in einer Liste von (Name, Wert) Paaren zurück, die nach Namen sortiert sind. Wenn das optionale Prädikatargument angegeben wird, werden nur Mitglieder eingeschlossen, für die das Prädikat einen wahren Wert zurückgibt.

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 
gimel
quelle
Ja, diese Antwort ist großartig. Ich habe dieses Modul noch nie benutzt. getmembers () wird implementiert, indem nur die Ergebnisse von dir (object) durchlaufen werden.
Nelson
Können Sie erläutern, warum dies besser ist als auf Diktate zuzugreifen ? Die Python-Dokumentation ist weniger hilfreich, insbesondere weil normalerweise der Begriff attributesanstelle von verwendet wird members(gibt es einen Unterschied zwischen den beiden?). Sie hätten den Namen in Python 3.0 korrigieren können, um ihn konsistent zu machen.
Nikow
Ups, meinte __dict__, tut mir leid.
Nikow
4
@nikow: inspect.getmembers () funktioniert garantiert auch dann weiter, wenn sich die internen Details ändern.
Georg Schölly
3
@NicholasKnight- inspect.getmembers()Wraps dir()mit den (meist vernachlässigbaren) Nebeneffekten von (A) einschließlich dynamischer Klassenattribute und Metaklassenattribute und (B) Ausschluss von Mitgliedern, die nicht mit dem übergebenen Prädikat übereinstimmen. Gähnen, richtig? inspect.getmembers()ist für Bibliotheken von Drittanbietern geeignet, die generisch alle möglichen Objekttypen unterstützen. Für Standardanwendungsfälle ist dies jedoch dir()absolut ausreichend.
Cecil Curry
66

dir()ist der einfache Weg. Siehe hier:

Leitfaden zur Python-Selbstbeobachtung

EBGreen
quelle
2
In den Python-Dokumenten ist etwas zu beachten, da dir () in erster Linie als Annehmlichkeit für die Verwendung an einer interaktiven Eingabeaufforderung bereitgestellt wird und mehr versucht, einen interessanten Satz von Namen als einen streng oder konsistent definierten Satz von Namen bereitzustellen, und Das detaillierte Verhalten kann sich je nach Version ändern. Beispielsweise befinden sich Metaklassenattribute nicht in der Ergebnisliste, wenn das Argument eine Klasse ist.
Skyler
1
Diese Antwort ist die beste, wenn Sie Scratch-Arbeiten an der CLI ausführen.
15 Jahre Python (kein Vollzeitjob) und ich vergesse immer noch dir()danke.
Abhishek Dujari
14

Die __dict__Eigenschaft des Objekts ist ein Wörterbuch aller anderen definierten Eigenschaften. Beachten Sie, dass Python-Klassen getattr überschreiben und Dinge erstellen können , die wie Eigenschaften aussehen, sich aber nicht in befinden __dict__. Es gibt auch die eingebauten Funktionen vars()und dir()die auf subtile Weise anders sind. Und __slots__kann __dict__in einigen ungewöhnlichen Klassen ersetzen .

Objekte sind in Python kompliziert. __dict__ist der richtige Ausgangspunkt für die Reflexionsprogrammierung. dir()ist der Ausgangspunkt, wenn Sie in einer interaktiven Shell herumhacken.

Nelson
quelle
print vars.__doc__zeigt an, With an argument, equivalent to object.__dict__also was wären die subtilen Unterschiede?
sancho.s ReinstateMonicaCellio
11

georg scholly kürzere version

print vars(theObject)
Nicolas Rojo
quelle
10

Wenn Sie alle Eigenschaften widerspiegeln möchten, sind die obigen Antworten großartig.

Wenn Sie nur nach den Schlüsseln eines Wörterbuchs suchen (das sich von einem 'Objekt' in Python unterscheidet), verwenden Sie

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']
MrE
quelle
1
Obwohl es meine Antwort ist, denke ich nicht, dass es die akzeptierte Antwort sein sollte: Die Schlüssel eines Objekts unterscheiden sich von der Eigenschaft einer Objektinstanz einer Klasse. Sie werden unterschiedlich ( obj['key']vs. obj.property) aufgerufen und die Frage betraf Objekteigenschaften. Ich habe hier meine Antwort gestellt, weil zwischen den beiden eine leichte Verwechslung besteht.
MrE
Ich würde tatsächlich vorschlagen, diese Antwort zu entfernen.
Ente
Wie oben erwähnt, werden Personen, die beispielsweise aus Javascript oder C # stammen, leicht durch die Terminologie verwirrt, da zwischen diesen beiden Konzepten kein Unterschied besteht. Leute, die Python lernen und versuchen, auf Schlüssel zuzugreifen, suchen sehr wahrscheinlich nach "Eigenschaften" und landen hier, weshalb ich denke, dass es dazu gehört.
MrE
und Sie haben Recht, aber verpassen Sie den Punkt: In anderen Sprachen (nehmen Sie JS) gibt es keinen Unterschied zwischen Objekt und Wörterbuch. Das OP kommt von C # und stellt die Frage. Obwohl diese Antwort falsch ist, hat sie 11 positive Stimmen erhalten, ein Beweis dafür, dass die Leute, die hier landen, sie nützlich finden, obwohl sie technisch nicht die richtige Antwort (wie ich erwähne) auf die Frage ist, wenn man sie in strenger Python-Sprache betrachtet. Ich werde es bearbeiten, um es noch kristallklarer zu machen.
MrE
5

Dies wird durch die anderen Antworten vollständig abgedeckt, aber ich werde es explizit machen. Ein Objekt kann Klassenattribute sowie statische und dynamische Instanzattribute aufweisen.

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasisist statisch, dynodynamisch (vgl. Eigenschaftsdekorator) und classyein Klassenattribut. Wenn wir es einfach tun __dict__oder varsnur die statische bekommen.

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

Wenn wir also wollen, bekommen die anderen __dict__alles (und mehr). Dies umfasst magische Methoden und Attribute sowie normal gebundene Methoden. Vermeiden wir also Folgendes:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

Die typemit einer Eigenschaft dekorierte Methode (ein dynamisches Attribut) gibt den Typ des zurückgegebenen Werts an, nicht method. Um dies zu beweisen, lassen Sie es von json stringifizieren:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

Wäre es eine Methode gewesen, wäre sie abgestürzt.

TL; DR. Versuchen Sie, extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}alle drei zu fordern , aber weder Methoden noch Magie.

Matteo Ferla
quelle