Existe-t-il une fonction intégrée pour imprimer toutes les propriétés et valeurs actuelles d'un objet?

Réponses:

591

Vous mélangez vraiment deux choses différentes.

Utilisez dir(), vars()ou le inspectmodule pour obtenir ce qui vous intéresse (j'utilise __builtins__comme exemple; vous pouvez utiliser n'importe quel objet à la place).

>>> l = dir(__builtins__)
>>> d = __builtins__.__dict__

Imprimez ce dictionnaire comme bon vous semble:

>>> print l
['ArithmeticError', 'AssertionError', 'AttributeError',...

ou

>>> from pprint import pprint
>>> pprint(l)
['ArithmeticError',
 'AssertionError',
 'AttributeError',
 'BaseException',
 'DeprecationWarning',
...

>>> pprint(d, indent=2)
{ 'ArithmeticError': <type 'exceptions.ArithmeticError'>,
  'AssertionError': <type 'exceptions.AssertionError'>,
  'AttributeError': <type 'exceptions.AttributeError'>,
...
  '_': [ 'ArithmeticError',
         'AssertionError',
         'AttributeError',
         'BaseException',
         'DeprecationWarning',
...

La jolie impression est également disponible dans le débogueur interactif en tant que commande:

(Pdb) pp vars()
{'__builtins__': {'ArithmeticError': <type 'exceptions.ArithmeticError'>,
                  'AssertionError': <type 'exceptions.AssertionError'>,
                  'AttributeError': <type 'exceptions.AttributeError'>,
                  'BaseException': <type 'exceptions.BaseException'>,
                  'BufferError': <type 'exceptions.BufferError'>,
                  ...
                  'zip': <built-in function zip>},
 '__file__': 'pass.py',
 '__name__': '__main__'}

la source
28
Étonnamment, il ne semble pas que tous les objets aient un __dict__membre (un re.MatchObjectpar exemple), mais la dir()fonction intégrée fonctionne pour tous les objets.
plaques
print re.compile(r'slots').search('No slots here either.').__slots__
plaques de cuisson
3
Nouveau pour moi. THX. Le point a déclenché l'analyseur de chemin de module de mon cerveau. Jamais même considéré le "module" latin.
plaques de cuisson
4
pourquoi ne parlez-vous pas plus du inspectmodule dans votre réponse? Je pense que c'est la chose la plus proche de print_r ou var_dump.
Hai Phaikawl
1
Comment accédez-vous aux valeurs derrière les attributs répertoriés par dir(), alors? dir()renvoie uniquement une liste de noms, et tous ceux-ci n'existent pas dans vars()ou dans l' __dict__attribut.
HelloGoodbye
981

Vous voulez vars()mélanger avec pprint():

from pprint import pprint
pprint(vars(your_object))
Jeremy Cantrell
la source
24
vars()retourne simplement le __dict__de son argument et c'est aussi la solution de secours dir()en cas d'absence de __dir__méthode. utilisez donc dir()en premier lieu, comme je l'ai dit.
28
@hop: dir()vous donne toutes les choses intégrées que vous n'aimez probablement pas comme __str__et __new__. var()non.
Timmmm
14
Cela échoue sur les ensembles et autres objets qui n'ont pas d' __dict__attribut.
anatoly techtonik
209
def dump(obj):
  for attr in dir(obj):
    print("obj.%s = %r" % (attr, getattr(obj, attr)))

Il existe de nombreuses fonctions tierces qui ajoutent des éléments tels que la gestion des exceptions, l'impression de caractères nationaux / spéciaux, la récurrence dans des objets imbriqués, etc. selon les préférences de leurs auteurs. Mais ils se résument tous à cela.

Dan Lenski
la source
5
antipythonique, car suit non-inventé-ici
14
Tu peux répéter s'il te plait? Bien sûr, vous pouvez utiliser la getmembers()fonction dans le inspectmodule standard , mais je pensais que cela serait plus utile car il illustre comment faire de l'introspection en général.
Dan Lenski
20
PAS DU TOUT. dir (obj) affiche les propriétés qui ne se trouvent pas dans __dict__(comme __doc__et __module__). De plus, __dict__ne fonctionne pas du tout pour les objets déclarés avec __slots__. En général, __dict__affiche les propriétés de niveau utilisateur qui sont réellement stockées dans un dictionnaire en interne. dir () en montre plus.
Dan Lenski
8
Certaines classes / objets ne contiennent aucun __dict__attribut / membre. Je sais que c'est fou, mais vrai. Les éléments intégrés tels que intet strou re.MatchObjects sont des exemples courants. Essayez 'hello'.__dict__, puis essayezdir('hello')
plaques de cuisson
11
Je me fiche que ce soit «impythonique» ou autre chose. Il fait le travail, ce qui, dans le débogage, est la seule et unique chose qui compte.
hidefromkgb
59

dir a été mentionné, mais cela ne vous donnera que les noms des attributs. Si vous voulez aussi leurs valeurs, essayez __dict__.

class O:
   def __init__ (self):
      self.value = 3

o = O()

Voici la sortie:

>>> o.__dict__

{'value': 3}
eduffy
la source
9
Des objets comme setça n'en ont pas __dict__, donc pour eux ça échouera avecAttributeError: 'set' object has no attribute '__dict__'
anatoly techtonik
23

Vous pouvez utiliser la fonction "dir ()" pour ce faire.

>>> import sys
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '__stdo
t__', '_current_frames', '_getframe', 'api_version', 'argv', 'builtin_module_names', 'byteorder
, 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'exc_clear', 'exc_info'
 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'getcheckinterval', 'getdefault
ncoding', 'getfilesystemencoding', 'getrecursionlimit', 'getrefcount', 'getwindowsversion', 'he
version', 'maxint', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_
ache', 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setprofile', 'setrecursionlimit
, 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoption
', 'winver']
>>>

Une autre fonctionnalité utile est l'aide.

>>> help(sys)
Help on built-in module sys:

NAME
    sys

FILE
    (built-in)

MODULE DOCS
    http://www.python.org/doc/current/lib/module-sys.html

DESCRIPTION
    This module provides access to some objects used or maintained by the
    interpreter and to functions that interact strongly with the interpreter.

    Dynamic objects:

    argv -- command line arguments; argv[0] is the script pathname if known
Joe Skora
la source
22

Pour imprimer l'état actuel de l'objet, vous pouvez:

>>> obj # in an interpreter

ou

print repr(obj) # in a script

ou

print obj

Pour vos classes définir __str__ou __repr__méthodes. Dans la documentation Python :

__repr__(self)Appelé par la repr()fonction intégrée et par les conversions de chaînes (guillemets inversés) pour calculer la représentation de chaîne "officielle" d'un objet. Si possible, cela devrait ressembler à une expression Python valide qui pourrait être utilisée pour recréer un objet avec la même valeur (dans un environnement approprié). Si cela n'est pas possible, une chaîne de la forme "<... une description utile ...>" doit être retournée. La valeur de retour doit être un objet chaîne. Si une classe définit repr () mais pas __str__(), elle __repr__()est également utilisée lorsqu'une représentation sous forme de chaîne "informelle" des instances de cette classe est requise. Ceci est généralement utilisé pour le débogage, il est donc important que la représentation soit riche en informations et sans ambiguïté.

__str__(self)Appelé par la str()fonction intégrée et par l'instruction print pour calculer la représentation de chaîne "informelle" d'un objet. Cela diffère du __repr__()fait qu'il ne doit pas nécessairement s'agir d'une expression Python valide: une représentation plus pratique ou concise peut être utilisée à la place. La valeur de retour doit être un objet chaîne.

jfs
la source
Cette option est utile pour imprimer des chaînes concaténées avec le contenu de l'objet:print "DEBUG: object value: " + repr(obj)
AlejandroVD
17

Cela vaut peut-être la peine d'être vérifié -

Existe-t-il un Python équivalent à Perl's Data :: Dumper?

Ma recommandation est la suivante -

https://gist.github.com/1071857

Notez que perl a un module appelé Data :: Dumper qui convertit les données d'objet en code source perl (NB: il ne convertit PAS le code en source, et presque toujours vous ne voulez pas que les fonctions de méthode objet dans la sortie). Cela peut être utilisé pour la persistance, mais le but commun est le débogage.

Il y a un certain nombre de choses que pprint python standard ne parvient pas à réaliser, en particulier il arrête simplement de descendre lorsqu'il voit une instance d'un objet et vous donne le pointeur hexadécimal interne de l'objet (errr, ce pointeur n'est pas très utilisé par le chemin). Donc, en un mot, python concerne tout ce grand paradigme orienté objet, mais les outils que vous sortez de la boîte sont conçus pour travailler avec autre chose que des objets.

Le Perl Data :: Dumper vous permet de contrôler jusqu'à quelle profondeur vous voulez aller, et détecte également les structures liées circulaires (c'est vraiment important). Ce processus est fondamentalement plus facile à réaliser en perl car les objets n'ont pas de magie particulière au-delà de leur bénédiction (un processus universellement bien défini).

Tél
la source
Cela devrait être un pip et un deb non seulement un gist!
phobie
2
> Donc en un mot, python est tout au sujet de ce grand paradigme orienté objet, mais les outils que vous sortez de la boîte sont conçus pour travailler avec autre chose que des objets ... Une affirmation quand le seul exemple que vous fournissez est un module d'importance secondaire.
memeplex
@memeplex où est-il dit que le python concerne la POO?
Peter Wood,
Ok, ça dit juste que tout tourne autour de cette grande POO, ma mauvaise.
memeplex
13

Je recommande d'utiliser help(your_object).

help(dir)

 If called without an argument, return the names in the current scope.
 Else, return an alphabetized list of names comprising (some of) the attributes
 of the given object, and of attributes reachable from it.
 If the object supplies a method named __dir__, it will be used; otherwise
 the default dir() logic is used and returns:
 for a module object: the module's attributes.
 for a class object:  its attributes, and recursively the attributes
 of its bases.
 for any other object: its attributes, its class's attributes, and
 recursively the attributes of its class's base classes.

help(vars)

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
prosti
la source
Oh, mec, +100500
Kirby
12

Dans la plupart des cas, en utilisant __dict__ou dir()vous obtiendrez les informations que vous recherchez. Si vous avez besoin de plus de détails, la bibliothèque standard comprend le module d' inspection , qui vous permet d'obtenir une quantité impressionnante de détails. Certains des vrais pépites d'informations comprennent:

  • noms des paramètres de fonction et de méthode
  • hiérarchies de classes
  • code source de l'implémentation d'une fonction / classe d'objets
  • variables locales hors d'un objet frame

Si vous cherchez simplement "quelles valeurs d'attribut mon objet a-t-il?", Alors dir()et __dict__sont probablement suffisantes. Si vous cherchez vraiment à creuser dans l'état actuel des objets arbitraires (en gardant à l'esprit qu'en python presque tout est un objet), alors cela inspectmérite d'être considéré.

William McVey
la source
Utilisé votre explication sur inspect pour améliorer la réponse la plus complète. J'espère que ça vous va.
Fernando César
10

Existe-t-il une fonction intégrée pour imprimer toutes les propriétés et valeurs actuelles d'un objet?

Non. La réponse la plus votée exclut certains types d'attributs et la réponse acceptée montre comment obtenir tous les attributs, y compris les méthodes et les parties de l'API non publique. Mais il n'y a pas de bonne fonction intégrée complète pour cela.

Donc, le court corollaire est que vous pouvez écrire le vôtre, mais il calculera les propriétés et autres descripteurs de données calculés qui font partie de l'API publique, et vous ne voudrez peut-être pas que:

from pprint import pprint
from inspect import getmembers
from types import FunctionType

def attributes(obj):
    disallowed_names = {
      name for name, value in getmembers(type(obj)) 
        if isinstance(value, FunctionType)}
    return {
      name: getattr(obj, name) for name in dir(obj) 
        if name[0] != '_' and name not in disallowed_names and hasattr(obj, name)}

def print_attributes(obj):
    pprint(attributes(obj))

Problèmes avec d'autres réponses

Observez l'application de la réponse actuellement la plus votée sur une classe avec beaucoup de différents types de membres de données:

from pprint import pprint

class Obj:
    __slots__ = 'foo', 'bar', '__dict__'
    def __init__(self, baz):
        self.foo = ''
        self.bar = 0
        self.baz = baz
    @property
    def quux(self):
        return self.foo * self.bar

obj = Obj('baz')
pprint(vars(obj))

imprime uniquement:

{'baz': 'baz'}

Parce vars que ne renvoie que l' __dict__objet d'un objet, et ce n'est pas une copie, donc si vous modifiez le dict retourné par vars, vous modifiez également __dict__l'objet de l'objet lui-même.

vars(obj)['quux'] = 'WHAT?!'
vars(obj)

Retour:

{'baz': 'baz', 'quux': 'WHAT?!'}

- ce qui est mauvais car quux est une propriété que nous ne devrions pas définir et ne devrions pas être dans l'espace de noms ...

Appliquer les conseils dans la réponse actuellement acceptée (et dans d'autres) n'est pas beaucoup mieux:

>>> dir(obj)
['__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__', '__slots__', '__str__', '__subclasshook__', 'bar', 'baz', 'foo', 'quux']

Comme nous pouvons le voir, dirne renvoie que tous (en fait juste la plupart) des noms associés à un objet.

inspect.getmembers, mentionné dans les commentaires, est également imparfait - il renvoie tous les noms et valeurs.

De classe

Lorsque j'enseigne, mes élèves créent une fonction qui fournit l'API sémantiquement publique d'un objet:

def api(obj):
    return [name for name in dir(obj) if name[0] != '_']

Nous pouvons étendre cela pour fournir une copie de l'espace de noms sémantique d'un objet, mais nous devons exclure ceux __slots__qui ne sont pas attribués, et si nous prenons au sérieux la demande de "propriétés actuelles", nous devons exclure les propriétés calculées (comme ils pourraient devenir coûteux et pourraient être interprétés comme n'étant pas "actuels"):

from types import FunctionType
from inspect import getmembers

def attrs(obj):
     disallowed_properties = {
       name for name, value in getmembers(type(obj)) 
         if isinstance(value, (property, FunctionType))}
     return {
       name: getattr(obj, name) for name in api(obj) 
         if name not in disallowed_properties and hasattr(obj, name)}

Et maintenant, nous ne calculons ni ne montrons la propriété, quux:

>>> attrs(obj)
{'bar': 0, 'baz': 'baz', 'foo': ''}

Avertissements

Mais nous savons peut-être que nos propriétés ne sont pas chères. Nous pouvons vouloir modifier la logique pour les inclure également. Et peut-être voulons-nous plutôt exclure d' autres descripteurs de données personnalisés .

Ensuite, nous devons personnaliser davantage cette fonction. Et il est donc logique que nous ne puissions pas avoir une fonction intégrée qui sait comme par magie exactement ce que nous voulons et la fournit. C'est une fonctionnalité dont nous avons besoin pour nous créer.

Conclusion

Il n'y a pas de fonction intégrée qui fait cela, et vous devez faire ce qui est le plus sémantiquement approprié à votre situation.

Aaron Hall
la source
Il y a une parenthèse très étroite après FunctionType. Mais très utile - merci!
nealmcb
@nealmcb merci je pense que je l'ai eu. Ravi d'être utile! :)
Aaron Hall
7

Un exemple de métaprogrammation Dump objet avec magie :

$ cat dump.py
#!/usr/bin/python
import sys
if len(sys.argv) > 2:
    module, metaklass  = sys.argv[1:3]
    m = __import__(module, globals(), locals(), [metaklass])
    __metaclass__ = getattr(m, metaklass)

class Data:
    def __init__(self):
        self.num = 38
        self.lst = ['a','b','c']
        self.str = 'spam'
    dumps   = lambda self: repr(self)
    __str__ = lambda self: self.dumps()

data = Data()
print data

Sans arguments:

$ python dump.py
<__main__.Data instance at 0x00A052D8>

Avec Gnosis Utils :

$ python dump.py gnosis.magic MetaXMLPickler
<?xml version="1.0"?>
<!DOCTYPE PyObject SYSTEM "PyObjects.dtd">
<PyObject module="__main__" class="Data" id="11038416">
<attr name="lst" type="list" id="11196136" >
  <item type="string" value="a" />
  <item type="string" value="b" />
  <item type="string" value="c" />
</attr>
<attr name="num" type="numeric" value="38" />
<attr name="str" type="string" value="spam" />
</PyObject>

Il est un peu dépassé mais fonctionne toujours.

jfs
la source
6

Si vous l'utilisez pour le débogage et que vous voulez juste un vidage récursif de tout, la réponse acceptée n'est pas satisfaisante car elle nécessite que vos classes aient __str__déjà de bonnes implémentations. Si ce n'est pas le cas, cela fonctionne beaucoup mieux:

import json
print(json.dumps(YOUR_OBJECT, 
                 default=lambda obj: vars(obj),
                 indent=1))
Adam Cath
la source
cela n'a pas fonctionné sur python 3. J'ai dû installer pymongo et le faire selon la réponse de @Clark
Tim Ogilvy
comme avec beaucoup d'autres réponses iciTypeError: vars() argument must have __dict__ attribute
volez
6

Essayez ppretty

from ppretty import ppretty


class A(object):
    s = 5

    def __init__(self):
        self._p = 8

    @property
    def foo(self):
        return range(10)


print ppretty(A(), show_protected=True, show_static=True, show_properties=True)

Production:

__main__.A(_p = 8, foo = [0, 1, ..., 8, 9], s = 5)
Symon
la source
exactement ce que je cherchais pour un débogage rapide :), super trouvaille!
Joseph Astrahan
petit indice ajouter profondeur = 6 (ou aussi loin que vous en avez besoin) comme l'un des paramètres et les détails de la récursivité peuvent aller plus loin :). L'une des choses que j'aime dans la façon dont il imprime les listes, c'est qu'il montre les 2 premières entrées et les 2 dernières entrées afin que vous sachiez que cela fonctionne
Joseph Astrahan
4
from pprint import pprint

def print_r(the_object):
    print ("CLASS: ", the_object.__class__.__name__, " (BASE CLASS: ", the_object.__class__.__bases__,")")
    pprint(vars(the_object))
32ndghost
la source
4

Ceci imprime récursivement tout le contenu de l'objet au format indenté json ou yaml:

import jsonpickle # pip install jsonpickle
import json
import yaml # pip install pyyaml

serialized = jsonpickle.encode(obj, max_depth=2) # max_depth is optional
print json.dumps(json.loads(serialized), indent=4)
print yaml.dump(yaml.load(serialized), indent=4)
wisbucky
la source
4

J'ai surévalué la réponse qui ne mentionne que pprint. Pour être clair, si vous voulez voir toutes les valeurs dans une structure de données complexe, faites quelque chose comme:

from pprint import pprint
pprint(my_var)

my_var est votre variable d'intérêt. Quand j'ai utilisépprint(vars(my_var)) je n'ai rien obtenu, et les autres réponses ici n'ont pas aidé ou la méthode semblait inutilement longue. Soit dit en passant, dans mon cas particulier, le code que j'inspectais avait un dictionnaire de dictionnaires.

Il convient de souligner qu'avec certaines classes personnalisées, vous pouvez vous retrouver avec un <someobject.ExampleClass object at 0x7f739267f400>type de sortie inutile . Dans ce cas, vous devrez peut-être implémenter une __str__méthode ou essayer certaines des autres solutions. J'aimerais toujours trouver quelque chose de simple qui fonctionne dans tous les scénarios, sans bibliothèques tierces.

Nagev
la source
3
> avec quelques classes personnalisées ... C'est pourquoi je ne suis pas fan de python. Les choses "parfois" fonctionnent et "parfois" pas
AlxVallejo
3

J'avais besoin d'imprimer les informations DEBUG dans certains journaux et je n'ai pas pu utiliser pprint car cela les casserait. Au lieu de cela, j'ai fait cela et j'ai pratiquement obtenu la même chose.

DO = DemoObject()

itemDir = DO.__dict__

for i in itemDir:
    print '{0}  :  {1}'.format(i, itemDir[i])
DaOneTwo
la source
3

Pour vider "myObject":

from bson import json_util
import json

print(json.dumps(myObject, default=json_util.default, sort_keys=True, indent=4, separators=(',', ': ')))

J'ai essayé vars () et dir (); les deux ont échoué pour ce que je cherchais. vars () n'a pas fonctionné car l'objet n'avait pas __dict__ (exceptions.TypeError: l'argument vars () doit avoir l'attribut __dict__). dir () n'était pas ce que je cherchais: c'est juste une liste de noms de champs, ne donne pas les valeurs ou la structure de l'objet.

Je pense que json.dumps () fonctionnerait pour la plupart des objets sans le défaut = json_util.default, mais j'avais un champ datetime dans l'objet donc le sérialiseur json standard a échoué. Voir Comment surmonter "datetime.datetime non JSON sérialisable" en python?

Clark
la source
D'accord, yep a dû installer pymongo tho pour l'utiliser.
Tim Ogilvy
3

Pourquoi pas quelque chose de simple:

for key,value in obj.__dict__.iteritems():
    print key,value
Michael Thamm
la source
N'est-ce pas for key,value in obj.__dict__.iteritems(): print key,value?
Raz
2

pprint contient une «jolie imprimante» pour produire des représentations esthétiques de vos structures de données. Le formateur produit des représentations de structures de données qui peuvent être analysées correctement par l'interpréteur et sont également faciles à lire pour un humain. La sortie est conservée sur une seule ligne, si possible, et indentée lorsqu'elle est divisée en plusieurs lignes.

shahjapan
la source
2

Essayez simplement l' empreinte d'abeille .

Cela vous aidera non seulement à imprimer des variables d'objet, mais aussi à obtenir une belle sortie, comme ceci:

class(NormalClassNewStyle):
  dicts: {
  },
  lists: [],
  static_props: 1,
  tupl: (1, 2)
Anyany Pan
la source
1
Ce module ne semble plus être maintenu et présente un certain nombre de problèmes en suspens. Utilisez plutôt ppretty
Wavesailor
1

Pour tout le monde aux prises avec

  • vars() ne renvoyant pas tous les attributs.
  • dir() ne renvoyant pas les valeurs des attributs.

Le code suivant imprime tous les attributs de objavec leurs valeurs:

for attr in dir(obj):
        try:
            print("obj.{} = {}".format(attr, getattr(obj, attr)))
        except AttributeError:
            print("obj.{} = ?".format(attr))
Robert Hönig
la source
ne pas avoir d'erreurs, mais pas récursif, alors obtenez simplement beaucoup d'adresses hexadécimales
volez
0

Vous pouvez essayer la barre d'outils de débogage Flask.
https://pypi.python.org/pypi/Flask-DebugToolbar

from flask import Flask
from flask_debugtoolbar import DebugToolbarExtension

app = Flask(__name__)

# the toolbar is only enabled in debug mode:
app.debug = True

# set a 'SECRET_KEY' to enable the Flask session cookies
app.config['SECRET_KEY'] = '<replace with a secret key>'

toolbar = DebugToolbarExtension(app)
Slipstream
la source
0

J'aime travailler avec des clés ou des valeurs de types intégrés d'objets python .

Pour les attributs, qu'il s'agisse de méthodes ou de variables:

o.keys()

Pour les valeurs de ces attributs:

o.values()
Evhz
la source
0

Cela fonctionne quelle que soit la façon dont vos variables sont définies au sein d'une classe, à l'intérieur de __init__ ou à l'extérieur.

your_obj = YourObj()
attrs_with_value = {attr: getattr(your_obj, attr) for attr in dir(your_obj)}
Carl Cheung
la source