Comment énumérer les propriétés d'un objet en Python?

133

IC # nous le faisons par réflexion. En Javascript, c'est simple comme:

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

Comment le faire en Python?

Jader Dias
la source
3
Veuillez noter que cette question est un abus de langage. La plupart des réponses concernent l'énumération des membres . Je cherchais un moyen d'énumérer les propriétés , c'est-à-dire les membres d'une classe décorée avec @property.
Tomasz Gandor

Réponses:

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

Sachez que dans de rares cas, il existe une __slots__propriété, ces classes n'en ont souvent pas __dict__.

Georg Schölly
la source
1
maintenant comment changer la valeur? en Javascript, vous pouvez faire: object [property] = newValue. Comment le faire en Python?
Jader Dias
39
utilisez plutôt setattr ().
Nelson
1
@Nelson Pourriez-vous expliquer pourquoi c'est une meilleure option? Est-ce simplement plus court ou y a-t-il des considérations supplémentaires?
WhyNotHugo
8
@Hugo: D'abord parce que c'est "pythonique", en d'autres termes c'est la syntaxe qu'une grande majorité de la communauté s'attend à voir. L'autre syntaxe mettrait probablement inutilement une pause à toute personne lisant votre code. Deuxièmement, certains types implémentent un setter __setattr__(). La définition de valeurs directement sur le dictionnaire contourne le setter de l'objet (et / ou ses parents). Il est assez courant en python que plus de choses que setattr()ce que vous voyez se produisent en arrière-plan lors de la définition des attributs (par exemple, l'assainissement), en utilisant garantit que vous ne les manquez pas, ou êtes obligé de les gérer vous-même explicitement.
Michael Ekoka
3
@ Salut-Angel Cela ne fait le travail. Ce qui ne fonctionne pas, cependant, c'est la constellation de préconceptions et d'hypothèses que vous avez autour du statut par rapport aux membres d'objets dynamiques en Python. vars()ne renvoie que les membres statiques (c'est-à-dire, les attributs d'objet et les méthodes enregistrés avec cet objet __dict__). Il ne renvoie pas de membres dynamiques (c'est-à-dire des attributs d'objet et des méthodes définis dynamiquement par la __getattr__()méthode de cet objet ou par une magie similaire). Selon toute vraisemblance, la file.ImplementationNamepropriété souhaitée est définie dynamiquement et n'est donc pas disponible pour vars()ou dir().
Cecil Curry le
69

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

Renvoie tous les membres d'un objet dans une liste de paires (nom, valeur) triées par nom. Si l'argument de prédicat facultatif est fourni, seuls les membres pour lesquels le prédicat renvoie une valeur vraie sont inclus.

>>> [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
la source
Ouais, cette réponse est géniale; jamais utilisé ce module auparavant. getmembers () est implémenté en parcourant simplement les résultats de dir (object), btw.
Nelson
Pouvez-vous expliquer pourquoi c'est mieux que d'accéder à dict ? La documentation Python est loin d'être utile, surtout parce qu'elle utilise normalement le terme à la attributesplace de members(y a-t-il une différence entre les deux?). Ils auraient pu corriger le nom dans Python 3.0 pour le rendre cohérent.
nikow
Oups, je veux dire __dict__, désolé.
nikow
4
@nikow: inspect.getmembers () est garanti de continuer à fonctionner même si les détails internes changent.
Georg Schölly
3
@NicholasKnight inspect.getmembers()enveloppements dir()avec les avantages secondaires ( la plupart du temps négligeable) de (A) , y compris les attributs de la classe dynamique et attributs de métaclasse et (B) à l' exclusion des membres ne correspondant le prédicat passé. Bailler, non? inspect.getmembers()convient aux bibliothèques tierces prenant en charge de manière générique tous les types d'objets possibles. Pour les cas d'utilisation standard, cependant, cela dir()suffit absolument.
Cecil Curry
66

dir()est le moyen le plus simple. Vois ici:

Guide de l'introspection Python

EBGreen
la source
2
Quelque chose à noter dans la documentation Python, car dir () est principalement fourni pour une utilisation pratique à une invite interactive, il essaie de fournir un ensemble intéressant de noms plus qu'il n'essaie de fournir un ensemble de noms défini de manière rigoureuse ou cohérente, et son comportement détaillé peut changer d'une version à l'autre. Par exemple, les attributs de métaclasse ne figurent pas dans la liste de résultats lorsque l'argument est une classe.
skyler
1
cette réponse est la meilleure lors du travail de scratch sur le cli.
15 ans de python (pas de travail à temps plein jamais) et j'oublie encore dir()merci.
Abhishek Dujari le
14

La __dict__propriété de l'objet est un dictionnaire de toutes ses autres propriétés définies. Notez que les classes Python peuvent remplacer getattr et créer des éléments qui ressemblent à des propriétés mais qui ne le sont pas __dict__. Il y a aussi les fonctions intégrées vars()et dir()qui sont différentes de manière subtile. Et __slots__peut remplacer __dict__dans certaines classes inhabituelles.

Les objets sont compliqués en Python. __dict__est le bon point de départ pour une programmation de type réflexion. dir()est le point de départ si vous piratez dans un shell interactif.

Nelson
la source
print vars.__doc__indique que With an argument, equivalent to object.__dict__Alors quelles seraient les différences subtiles?
sancho.s ReinstateMonicaCellio
11

georg scholly version plus courte

print vars(theObject)
Nicolas Rojo
la source
10

Si vous recherchez le reflet de toutes les propriétés, les réponses ci-dessus sont excellentes.

Si vous cherchez simplement à obtenir les clés d'un dictionnaire (qui est différent d'un 'objet' en Python), utilisez

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']
MrE
la source
1
même si c'est ma réponse, je ne pense pas que ce devrait être la réponse acceptée: les clés d'un objet sont différentes de la propriété d'une instance d'objet d'une classe. On y accède différemment ( obj['key']vs. obj.property) et la question portait sur les propriétés des objets. Je mets ma réponse ici car il y a une confusion facile entre les deux.
MrE
Je suggérerais en fait de supprimer cette réponse.
Ente
Comme indiqué ci-dessus, les personnes venant de Javascript ou de C # par exemple sont facilement confondues par la terminologie car il n'y a aucune différence entre ces 2 concepts. Les personnes qui apprennent python et essaient d'accéder aux clés sont très susceptibles de rechercher des `` propriétés '' et de se retrouver ici, d'où je pense qu'il appartient.
MrE
et vous avez raison, mais manquez le point: dans d'autres langues (prenez JS), il n'y a pas de distinction entre objet et dictionnaire. L'OP vient de C # posant la question. Cette réponse, bien que fausse, a obtenu 11 votes positifs, preuve que les gens qui atterrissent ici la trouvent utile, même si ce n'est pas techniquement la bonne réponse (comme je le souligne) à la question quand on la regarde dans le jargon python strict. Je vais modifier pour le rendre encore plus clair.
MrE
5

Ceci est totalement couvert par les autres réponses, mais je vais le rendre explicite. Un objet peut avoir des attributs de classe et des attributs d'instance statiques et dynamiques.

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

    def fx(self):
        return 3

stasisest statique, dynodynamique (cf. propriété décorateur) et classyest un attribut de classe. Si nous faisons simplement __dict__ou varsnous n'obtiendrons que le statique.

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

Donc, si nous voulons, les autres __dict__auront tout (et plus). Cela inclut les méthodes et attributs magiques et les méthodes liées normales. Alors évitons ceux-ci:

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 typeméthode appelée avec une propriété décorée (un attribut dynamique) vous donnera le type de la valeur retournée, non method. Pour prouver cela, json le stringify:

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

Si cela avait été une méthode, cela se serait écrasé.

TL et DR. essayez d'appeler extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}les trois, mais pas de méthodes ni de magie.

Matteo Ferla
la source