Come enumerare le proprietà di un oggetto in Python?


133

IC # lo facciamo attraverso la riflessione. In Javascript è semplice come:

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

Come farlo in Python?



3
Questa domanda è errata. La maggior parte delle risposte riguarda l'enumerazione dei membri . Stavo cercando un modo per elencare le proprietà , cioè i membri di una classe decorata con @property.
Tomasz Gandor,

Risposte:


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

Tieni presente che in alcuni rari casi esiste una __slots__proprietà, tali classi spesso non ne hanno __dict__.


1
ora come modificare il valore? in Javascript potresti fare: object [proprietà] = newValue. Come farlo in Python?
Jader Dias,

39
usa invece setattr ().
Nelson,

1
@Nelson Potresti spiegare perché questa è un'opzione migliore? È solo più breve o ci sono ulteriori considerazioni?
WhyNotHugo,

8
@Hugo: Innanzitutto perché è "pitonico", in altre parole è la sintassi che la maggior parte della comunità si aspetta di vedere. L'altra sintassi probabilmente farebbe inutilmente pausa a chiunque legga il tuo codice. In secondo luogo, alcuni tipi implementano un setter __setattr__(). L'impostazione dei valori direttamente sul dizionario ignora il setter dell'oggetto (e / o dei suoi genitori). È abbastanza comune in Python che durante l'impostazione degli attributi (ad es. Servizi igienico-sanitari) stiano accadendo più cose di quanto si pensi all'occhio, usando si setattr()assicura che non si perda o si sia costretti a gestirle esplicitamente.
Michael Ekoka,

3
@ Hi-angelo che fa il lavoro. Ciò che non funziona, tuttavia, è la costellazione di preconcetti e ipotesi che hai lo stato circostante rispetto ai membri di oggetti dinamici in Python. vars()restituisce solo membri statici (ovvero attributi e metodi degli oggetti registrati con quelli di quell'oggetto __dict__). Esso non ritorno utenti dinamici (cioè gli attributi degli oggetti e metodi definiti dinamicamente quell'oggetto __getattr__()metodo o magia simile). Con ogni probabilità, la file.ImplementationNameproprietà desiderata viene definita in modo dinamico e quindi non disponibile per vars()o dir().
Cecil Curry,

69

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

Restituisce tutti i membri di un oggetto in un elenco di coppie (nome, valore) ordinate per nome. Se viene fornito l'argomento predicato facoltativo, vengono inclusi solo i membri per i quali il predicato restituisce un valore vero.

>>> [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']
>>> 

Sì, questa risposta è fantastica; mai usato questo modulo prima. getmembers () è implementato semplicemente camminando sui risultati di dir (oggetto), tra l'altro.
Nelson,

Puoi spiegare perché questo è meglio dell'accesso a dict ? La documentazione di Python è poco utile, soprattutto perché normalmente usa il termine attributesinvece di members(c'è qualche differenza tra i due?). Avrebbero potuto correggere il nome in Python 3.0 per renderlo coerente.
nikow,

Oops, volevo dire __dict__, scusa.
nikow,

4
@nikow: inspect.getmembers () è garantito per continuare a funzionare anche se i dettagli interni cambiano.
Georg Schölly,

3
@NicholasKnight inspect.getmembers()impacchi dir()con (principalmente trascurabili) vantaggi collaterali di (A) compresi gli attributi di classe dinamica e attributi metaclasse e (B) , escluso l' non corrispondenti al predicato passato. Sbadiglio, vero? inspect.getmembers()è appropriato per le librerie di terze parti che supportano genericamente tutti i possibili tipi di oggetti. Per i casi d'uso standard, tuttavia, è dir()assolutamente sufficiente.
Cecil Curry,

66

dir()è il modo semplice. Vedere qui:

Guida all'introspezione di Python


2
Qualcosa da notare dai documenti di Python, poiché dir () viene fornito principalmente come comodità per l'uso a un prompt interattivo, cerca di fornire un set di nomi interessante più di quanto non cerchi di fornire un set di nomi rigorosamente o coerentemente definito, e il suo comportamento dettagliato può cambiare tra le versioni. Ad esempio, gli attributi della metaclasse non sono nell'elenco dei risultati quando l'argomento è una classe.
skyler,

1
questa risposta è la migliore quando si eseguono lavori di scratch sul cli.

15 anni di pitone (non lavoro a tempo pieno mai) e ancora dimentico dir()grazie.
Abhishek Dujari,

14

La __dict__proprietà dell'oggetto è un dizionario di tutte le altre proprietà definite. Nota che le classi Python possono sovrascrivere getattr e creare cose che sembrano proprietà ma non ci sono __dict__. Ci sono anche le funzioni integrate vars()e dir()che sono diverse in modo sottile. E __slots__può sostituire __dict__in alcune classi insolite.

Gli oggetti sono complicati in Python. __dict__è il posto giusto da cui iniziare la programmazione in stile riflessivo. dir()è il punto di partenza se stai hackerando in una shell interattiva.


print vars.__doc__indica che With an argument, equivalent to object.__dict__Quindi quali sarebbero le sottili differenze?
sancho.s RipristinaMonicaCellio il


10

Se stai cercando il riflesso di tutte le proprietà, le risposte sopra sono ottime.

Se stai semplicemente cercando di ottenere le chiavi di un dizionario (che è diverso da un 'oggetto' in Python), usa

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']

1
anche se è la mia risposta, non penso che dovrebbe essere la risposta accettata: le chiavi di un oggetto sono diverse dalla proprietà di un'istanza di oggetto di una classe. Sono accessibili in modo diverso ( obj['key']vs. obj.property) e la domanda riguardava le proprietà degli oggetti. Ho messo la mia risposta qui perché c'è una facile confusione tra i due.
MrE

In realtà suggerirei di rimuovere questa risposta.
Ente,

Come detto sopra, le persone che provengono da Javascript o C # per esempio sono facilmente confuse dalla terminologia in quanto non vi è alcuna differenza tra questi 2 concetti. Le persone che imparano Python e provano ad accedere alle chiavi hanno molto probabilità di cercare "proprietà" e finire qui, quindi perché penso che appartenga.
MrE

e hai ragione, ma manca il punto: in altre lingue (prendi JS) non c'è distinzione tra oggetto e dizionario. L'OP proviene da C # che pone la domanda. Questa risposta, sebbene sbagliata, ha ottenuto 11 voti positivi, a dimostrazione del fatto che le persone che atterrano qui la trovano utile, anche se tecnicamente non è la risposta giusta (come faccio notare) alla domanda quando la guardano in un gergo di pitone rigoroso. Modificherò per renderlo ancora più cristallino.
MrE

5

Questo è totalmente coperto dalle altre risposte, ma lo renderò esplicito. Un oggetto può avere attributi di classe e attributi di istanza statici e dinamici.

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

    def fx(self):
        return 3

stasisè statico, dynodinamico (vedi decoratore di proprietà) ed classyè un attributo di classe. Se lo facciamo semplicemente __dict__o varsavremo solo quello statico.

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

Quindi se vogliamo che gli altri __dict__otterranno tutto (e altro). Ciò include metodi e attributi magici e metodi associati normali. Quindi evitiamo quelli:

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}

La typechiamata con un metodo decorato con proprietà (un attributo dinamico) ti darà il tipo del valore restituito, no method. Per dimostrarlo, Json lo stringe:

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

Se fosse stato un metodo si sarebbe schiantato.

TL; DR. prova a chiamare extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}tutti e tre, ma non metodi né magia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.