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.