Liste les attributs d'un objet

330

Existe-t-il un moyen de récupérer une liste d'attributs qui existent sur les instances d'une classe?

class new_class():
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

a = new_class(2)
print(', '.join(a.SOMETHING))

Le résultat souhaité est que "multi, str" sera émis. Je veux que cela voit les attributs actuels de diverses parties d'un script.

MadSc13ntist
la source
75
Pratiquement tout le monde en Python nomme ses classes comme NewClass. Vous pouvez défier les attentes des gens si vous utilisez une convention de dénomination comme new_class.
Mike Graham
Même si elle est interactive et ne peut pas être utilisée par programme, la help()fonction aide à obtenir des informations sur les classes, les fonctions, les modules internes, les modules, etc.
ytpillai
1
Pertinent: stackoverflow.com/questions/1398022/…
sancho.s ReinstateMonicaCellio
Pourquoi aucune des réponses n'est-elle marquée comme «acceptée»?
pfabri

Réponses:

295
>>> class new_class():
...   def __init__(self, number):
...     self.multi = int(number) * 2
...     self.str = str(number)
... 
>>> a = new_class(2)
>>> a.__dict__
{'multi': 4, 'str': '2'}
>>> a.__dict__.keys()
dict_keys(['multi', 'str'])

Vous pouvez également trouver pprint utile.


la source
29
Le problème de l' utilisation de dict vient d'apparaître sur r / python. quelqu'un a souligné que vars (a) est équivalent à un .__ dict__
David
5
Si quelqu'un se pose la question, cela fonctionne également sur Python 2.7
Ben Mordecai
8
Pour être précis, pprint.pprint(a.__dict__)fait une jolie impression sur les attributs.
smci
1
Certainement, cela pprintne fonctionne PAS sur Python 2.6.
John Greene
3
Notez que cela ne fonctionne que pour les classes définies par l'utilisateur, pas pour les types intégrés ou d'extension.
ivan_pozdeev
173
dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

Ensuite, vous pouvez tester avec quel type est type()ou si est une méthode avec callable().

Htechno
la source
dir fonctionnait mieux sur les classes avec l'attribut surchargé get / set
ogurets
dir (instance) répertorie beaucoup de choses qui ne vous intéressent probablement pas
jciloa
C'était la seule fonction qui m'a obtenu tous les attributs disponibles sur l' bostonensemble de données de sklearn - __dict__était vide, alors qu'en fait il y avait 5 attributs disponibles
Coruscate5
72

vars(obj) renvoie les attributs d'un objet.

rohithpr
la source
54

Toutes les réponses précédentes sont correctes, vous avez trois options pour ce que vous demandez

  1. dir()

  2. vars()

  3. __dict__

>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']
>>> vars(a)
{'multi': 4, 'str': '2'}
>>> a.__dict__
{'multi': 4, 'str': '2'}
grepit
la source
1
vars(foo)retoursfoo.__dict__
Boris
32
>>> ', '.join(i for i in dir(a) if not i.startswith('__'))
'multi, str'

Bien sûr, cela imprimera toutes les méthodes ou attributs de la définition de classe. Vous pouvez exclure les méthodes « privées » en changeant i.startwith('__')dei.startwith('_')

SilentGhost
la source
24

Le module d' inspection fournit des moyens simples d'inspecter un objet:

Le module d'inspection fournit plusieurs fonctions utiles pour vous aider à obtenir des informations sur les objets actifs tels que les modules, les classes, les méthodes, les fonctions, les retraits, les objets de trame et les objets de code.


En utilisant, getmembers()vous pouvez voir tous les attributs de votre classe, ainsi que leur valeur. Pour exclure des attributs privés ou protégés, utilisez .startswith('_'). Pour exclure des méthodes ou des fonctions, utilisez inspect.ismethod()ou inspect.isfunction().

import inspect


class NewClass(object):
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

    def func_1(self):
        pass


a = NewClass(2)

for i in inspect.getmembers(a):
    # Ignores anything starting with underscore 
    # (that is, private and protected attributes)
    if not i[0].startswith('_'):
        # Ignores methods
        if not inspect.ismethod(i[1]):
            print(i)

Notez qu'il ismethod()est utilisé sur le deuxième élément de ipuisque le premier est simplement une chaîne (son nom).

Hors sujet : utilisez CamelCase pour les noms de classe.

Paradoxe de Fermi
la source
13

Vous pouvez utiliser dir(your_object)pour obtenir les attributs et getattr(your_object, your_object_attr)obtenir les valeurs

utilisation:

for att in dir(your_object):
    print (att, getattr(your_object,att))

Ceci est particulièrement utile si votre objet n'a pas de __dict__. Si ce n'est pas le cas, vous pouvez également essayer var (your_object)

Jason Angel
la source
11

Il est souvent mentionné que pour répertorier une liste complète des attributs que vous devez utiliser dir(). Notez cependant que contrairement à la croyance populaire dir()ne fait pas ressortir tous les attributs. Par exemple, vous remarquerez __name__peut-être qu'il manque dans la dir()liste d'une classe même si vous pouvez y accéder depuis la classe elle-même. Depuis la doc dir()( Python 2 , Python 3 ):

Étant donné que dir () est fourni principalement à des fins de commodité à une invite interactive, il essaie de fournir un ensemble de noms intéressant plus qu'il ne tente 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.

Une fonction comme la suivante a tendance à être plus complète, bien qu'il n'y ait aucune garantie d'exhaustivité, car la liste renvoyée par dir()peut être affectée par de nombreux facteurs, notamment la mise en œuvre de la __dir__()méthode, la personnalisation __getattr__()ou __getattribute__()la classe ou l'un de ses parents. Voir les liens fournis pour plus de détails.

def dirmore(instance):
    visible = dir(instance)
    visible += [a for a in set(dir(type)).difference(visible)
                if hasattr(instance, a)]
    return sorted(visible)
Michael Ekoka
la source
9

Pourquoi voulez-vous cela? Il peut être difficile de vous obtenir la meilleure réponse sans connaître votre intention exacte.

  • Il est presque toujours préférable de le faire manuellement si vous souhaitez afficher une instance de votre classe d'une manière spécifique. Cela comprendra exactement ce que vous voulez et non ce que vous ne voulez pas, et la commande sera prévisible.

    Si vous cherchez un moyen d'afficher le contenu d'une classe, formatez manuellement les attributs qui vous intéressent et fournissez-le comme méthode __str__ou __repr__pour votre classe.

  • Si vous voulez en savoir plus sur les méthodes et celles qui existent pour qu'un objet comprenne comment il fonctionne, utilisez help. help(a)vous montrera une sortie formatée sur la classe de l'objet en fonction de ses docstrings.

  • direxiste pour obtenir par programmation tous les attributs d'un objet. (L'accès __dict__fait quelque chose que je regrouperais de la même façon mais que je ne me servirais pas moi-même.) Cependant, cela peut ne pas inclure les choses que vous voulez et cela peut inclure des choses que vous ne voulez pas. Ce n'est pas fiable et les gens pensent qu'ils le veulent beaucoup plus souvent qu'eux.

  • Sur une note quelque peu orthogonale, il y a très peu de support pour Python 3 à l'heure actuelle. Si vous êtes intéressé par l'écriture de vrais logiciels, vous allez vouloir des trucs tiers comme numpy, lxml, Twisted, PIL, ou un certain nombre de frameworks Web qui ne prennent pas encore en charge Python 3 et ne prévoient pas trop tôt. Les différences entre 2.6 et la branche 3.x sont petites, mais la différence dans le support de bibliothèque est énorme.

Mike Graham
la source
4
Je voudrais juste souligner que cinq ans plus tard (maintenant), je crois que tous les modules tiers que vous mentionnez prennent en charge python3. Source: python3wos.appspot.com
pzkpfw
8

Il y a plus d'une façon de le faire:

#! /usr/bin/env python3
#
# This demonstrates how to pick the attiributes of an object

class C(object) :

  def __init__ (self, name="q" ):
    self.q = name
    self.m = "y?"

c = C()

print ( dir(c) )

Lorsqu'il est exécuté, ce code produit:

jeffs@jeff-desktop:~/skyset$ python3 attributes.py 
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__',      '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm', 'q']

jeffs@jeff-desktop:~/skyset$
user1928764
la source
2
Pourquoi cette réponse a été rejetée? À des fins de débogage, dir fonctionne plutôt bien!
Dunatotatos
Fonctionne assez bien avec Python 2.7.x. Exactement ce que je voulais.
Davidson Lima
7

Veuillez voir le script shell python qui a été exécuté en séquence, ici vous obtiendrez les attributs d'une classe au format chaîne séparés par des virgules.

>>> class new_class():
...     def __init__(self, number):
...         self.multi = int(number)*2
...         self.str = str(number)
... 
>>> a = new_class(4)
>>> ",".join(a.__dict__.keys())
'str,multi'<br/>

J'utilise python 3.4

Lokesh kumar
la source
Et si vous le souhaitez, seule la liste peut être utilisée simplement a.__dict__.keys(). Cependant, si vous voulez savoir si un objet a un attribut spécifique, vous pouvez l'utiliser hasattr.
berna1111
4

En plus de ces réponses, j'inclurai une fonction (python 3) pour cracher pratiquement toute la structure de n'importe quelle valeur. Il utilise dirpour établir la liste complète des noms de propriété, puis utilise getattravec chaque nom. Il affiche le type de chaque membre de la valeur et, si possible, affiche également le membre entier:

import json

def get_info(obj):

  type_name = type(obj).__name__
  print('Value is of type {}!'.format(type_name))
  prop_names = dir(obj)

  for prop_name in prop_names:
    prop_val = getattr(obj, prop_name)
    prop_val_type_name = type(prop_val).__name__
    print('{} has property "{}" of type "{}"'.format(type_name, prop_name, prop_val_type_name))

    try:
      val_as_str = json.dumps([ prop_val ], indent=2)[1:-1]
      print('  Here\'s the {} value: {}'.format(prop_name, val_as_str))
    except:
      pass

Maintenant, l'un des éléments suivants devrait donner un aperçu:

get_info(None)
get_info('hello')

import numpy
get_info(numpy)
# ... etc.
Gershom
la source
Wow, c'est un bijou!
pfabri
ouais c'était une bouée de sauvetage. n'a pas pu comprendre pourquoi cela je ne pouvais pas facilement décompresser ces listes et bien sûr le type a la propriété " slots " de type "tuple" Voici la valeur des slots : ["nsname", "hostmaster", "serial", "refresh", "réessayer", "expire", "minttl", "ttl"]
Mik R
3

Récupère les attributs d'un objet

class new_class():
    def __init__(self, number):
    self.multi = int(number) * 2
    self.str = str(number)

new_object = new_class(2)                
print(dir(new_object))                   #total list attributes of new_object
attr_value = new_object.__dict__         
print(attr_value)                        #Dictionary of attribute and value for new_class                   

for attr in attr_value:                  #attributes on  new_class
    print(attr)

Production

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__','__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']

{'multi': 4, 'str': '2'}

multi
str
Béni
la source
1

Comme écrit avant, l'utilisation obj.__dict__peut gérer les cas courants, mais certaines classes n'ont pas l' __dict__attribut et l'utilisation __slots__(principalement pour l'efficacité de la mémoire).

exemple pour une façon plus résiliente de le faire:

class A(object):
    __slots__ = ('x', 'y', )
    def __init__(self, x, y):
        self.x = x
        self.y = y


class B(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


def get_object_attrs(obj):
    try:
        return obj.__dict__
    except AttributeError:
        return {attr: getattr(obj, attr) for attr in obj.__slots__}


a = A(1,2)
b = B(1,2)
assert not hasattr(a, '__dict__')

print(get_object_attrs(a))
print(get_object_attrs(b))

la sortie de ce code:

{'x': 1, 'y': 2}
{'x': 1, 'y': 2}

Remarque 1:
Python est un langage dynamique et il est toujours préférable de connaître les classes dont vous essayez d'obtenir les attributs car même ce code peut manquer certains cas.

Remarque 2:
ce code ne produit que des variables d'instance, ce qui signifie que les variables de classe ne sont pas fournies. par exemple:

class A(object):
    url = 'http://stackoverflow.com'
    def __init__(self, path):
        self.path = path

print(A('/questions').__dict__)

sorties de code:

{'path': '/questions'}

Ce code n'imprime pas l' urlattribut de classe et peut omettre les attributs de classe souhaités.
Parfois, nous pouvons penser qu'un attribut est un membre d'instance, mais il n'est pas et ne sera pas affiché à l'aide de cet exemple.

ShmulikA
la source
2
Une classe peut avoir __dict__ et __slots__ , donc vous voudrez probablement essayer les deux plutôt que juste le dict.
cz
1
  • Utiliser __dict__ou vars ne fonctionne pas car il manque __slots__.
  • Utiliser __dict__et __slots__ ne fonctionne pas car il manque les __slots__classes de base.
  • L'utilisation dir ne fonctionne pas car elle inclut des attributs de classe, tels que des méthodes ou des propriétés, ainsi que les attributs d'objet.
  • Utiliser varséquivaut à utiliser __dict__.

C'est le meilleur que j'ai:

from typing import Dict

def get_attrs( x : object ) -> Dict[str, object]:
    mro      = type( x ).mro()
    attrs    = { }
    has_dict = False
    sentinel = object()

    for klass in mro:
        for slot in getattr( klass, "__slots__", () ):
            v = getattr( x, slot, sentinel )

            if v is sentinel:
                continue

            if slot == "__dict__":
                assert not has_dict, "Multiple __dicts__?"
                attrs.update( v )
                has_dict = True
            else:
                attrs[slot] = v

    if not has_dict:
        attrs.update( getattr( x, "__dict__", { } ) )

    return attrs
cz
la source
Appliquons cette fonction à une classe simple spome: classe C: def __init __ (self): print ("created") i = 42 Pourquoi votre code donne une liste vide pour une telle classe? (Je veux dire si o = C () alors get_attrs (o) est vide) Il l'a également fait pour get_attrs ("mystr")
ged
0
attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]
shammerw0w
la source
Il ne fonctionne pas avec les noms d'attribut de classe commençant par une majuscule ou un seul trait de soulignement.
fviktor
0

Veuillez voir l'exécution des scripts de shell Python suivante dans l'ordre, cela donnera la solution de la création de classe à l'extraction des noms de champ des instances.

>>> class Details:
...       def __init__(self,name,age):
...           self.name=name
...           self.age =age
...       def show_details(self):
...           if self.name:
...              print "Name : ",self.name
...           else:
...              print "Name : ","_"
...           if self.age:
...              if self.age>0:
...                 print "Age  : ",self.age
...              else:
...                 print "Age can't be -ve"
...           else:
...              print "Age  : ","_"
... 
>>> my_details = Details("Rishikesh",24)
>>> 
>>> print my_details
<__main__.Details instance at 0x10e2e77e8>
>>> 
>>> print my_details.name
Rishikesh
>>> print my_details.age
24
>>> 
>>> my_details.show_details()
Name :  Rishikesh
Age  :  24
>>> 
>>> person1 = Details("",34)
>>> person1.name
''
>>> person1.age
34
>>> person1.show_details
<bound method Details.show_details of <__main__.Details instance at 0x10e2e7758>>
>>> 
>>> person1.show_details()
Name :  _
Age  :  34
>>>
>>> person2 = Details("Rob Pike",0)
>>> person2.name
'Rob Pike'
>>> 
>>> person2.age
0
>>> 
>>> person2.show_details()
Name :  Rob Pike
Age  :  _
>>> 
>>> person3 = Details("Rob Pike",-45)
>>> 
>>> person3.name
'Rob Pike'
>>> 
>>> person3.age
-45
>>> 
>>> person3.show_details()
Name :  Rob Pike
Age can't be -ve
>>>
>>> person3.__dict__
{'age': -45, 'name': 'Rob Pike'}
>>>
>>> person3.__dict__.keys()
['age', 'name']
>>>
>>> person3.__dict__.values()
[-45, 'Rob Pike']
>>>
hygull
la source
Nous pouvons également vérifier la callabilité de chaque attribut.visit stackoverflow.com/questions/1398022/…
hygull
-4

__attr__ donne la liste des attributs d'une instance.

>>> import requests
>>> r=requests.get('http://www.google.com')
>>> r.__attrs__
['_content', 'status_code', 'headers', 'url', 'history', 'encoding', 'reason', 'cookies', 'elapsed', 'request']
>>> r.url
'http://www.google.com/'
>>>
Vivek
la source
Ça ne marche pas toujours. De plus, vous écrivez __attr__dans la description mais utilisez __attrs__dans le code. Aucun n'a fonctionné pour moi (werkzeug.datastructures.FileStorage)
Jonas