¿Existe una función incorporada para imprimir todas las propiedades y valores actuales de un objeto?

Respuestas:

591

Realmente estás mezclando dos cosas diferentes.

Uso dir(), vars()o el inspectmódulo para conseguir lo que le interesa (utilizo __builtins__como ejemplo, se puede utilizar cualquier objeto en su lugar).

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

Imprime ese diccionario como quieras:

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

o

>>> 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 impresión bonita también está disponible en el depurador interactivo como un comando:

(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__'}

fuente
28
Sorprendentemente, parece que no todos los objetos tienen un __dict__miembro (un re.MatchObjectpor ejemplo), pero incorporado dir()funciona para todos los objetos.
placas el
print re.compile(r'slots').search('No slots here either.').__slots__
placas el
3
Nuevo para mi. Gracias. El punto activó el analizador de ruta del módulo de mi cerebro. Nunca consideró el "módulo" latino.
encimeras
44
¿Por qué no hablas más sobre el inspectmódulo en tu respuesta? Creo que es lo más parecido a print_r o var_dump.
Hai Phaikawl
1
¿Cómo se accede a los valores detrás de los atributos enumerados por dir(), entonces? dir()solo devuelve una lista de nombres, y no todos existen en vars()o en el __dict__atributo.
Hola
981

Quieres vars()mezclar con pprint():

from pprint import pprint
pprint(vars(your_object))
Jeremy Cantrell
fuente
24
vars()simplemente devuelve el __dict__de su argumento y ese también es el respaldo de dir()en caso de que no haya ningún __dir__método. así que dir()en primer lugar, como dije.
28
@hop: dir()te ofrece todas las cosas integradas que probablemente no te interesen __str__y __new__. var()no lo hace
Timmmm
14
Esto falla en conjuntos y otros objetos que no tienen __dict__atributo.
anatoly techtonik
209
def dump(obj):
  for attr in dir(obj):
    print("obj.%s = %r" % (attr, getattr(obj, attr)))

Existen muchas funciones de terceros que agregan cosas como manejo de excepciones, impresión de caracteres nacionales / especiales, recursión en objetos anidados, etc. de acuerdo con las preferencias de sus autores. Pero todos básicamente se reducen a esto.

Dan Lenski
fuente
55
antipático, porque sigue no inventado aquí
14
¿Que qué? Claro, puede usar la getmembers()función en el inspectmódulo estándar , pero pensé que esto sería más útil ya que ilustra cómo hacer la introspección en general.
Dan Lenski,
20
DE NINGÚN MODO. dir (obj) muestra propiedades que no se encuentran en __dict__(como __doc__y __module__). Además, __dict__no funciona en absoluto para los objetos declarados con __slots__. En general, __dict__muestra las propiedades de nivel de usuario que realmente se almacenan internamente en un diccionario. dir () muestra más.
Dan Lenski,
8
Algunas clases / objetos no contienen ningún __dict__atributo / miembro. Sé que es una locura, pero cierto. Los empotrados como inty stro re.MatchObjects son ejemplos comunes. Intenta 'hello'.__dict__, luego intentadir('hello')
hobs
11
No me importa si eso es "antipático" o no. Hace el trabajo, que en la depuración es lo único que importa.
hidefromkgb
59

se ha mencionado dir , pero eso solo le dará los nombres de los atributos. Si también quieres sus valores, prueba __dict__.

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

o = O()

Aquí está la salida:

>>> o.__dict__

{'value': 3}
eduffy
fuente
99
Objetos como setno tiene __dict__, por lo que para ellos fallaráAttributeError: 'set' object has no attribute '__dict__'
anatoly techtonik
23

Puede usar la función "dir ()" para hacer esto.

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

Otra característica útil es la ayuda.

>>> 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
fuente
22

Para imprimir el estado actual del objeto, puede:

>>> obj # in an interpreter

o

print repr(obj) # in a script

o

print obj

Para sus clases definir __str__o __repr__métodos. De la documentación de Python :

__repr__(self)Llamado por la repr()función incorporada y por las conversiones de cadena (comillas inversas) para calcular la representación de cadena "oficial" de un objeto. Si es posible, esto debería verse como una expresión Python válida que podría usarse para recrear un objeto con el mismo valor (dado un entorno apropiado). Si esto no es posible, se debe devolver una cadena de la forma "<... alguna descripción útil ...>". El valor de retorno debe ser un objeto de cadena. Si una clase define repr () pero no __str__(), entonces __repr__()también se usa cuando se requiere una representación de cadena "informal" de instancias de esa clase. Esto generalmente se usa para la depuración, por lo que es importante que la representación sea rica en información y sin ambigüedades.

__str__(self)Llamado por la str()función incorporada y por la instrucción print para calcular la representación de cadena "informal" de un objeto. Esto difiere de __repr__()que no tiene que ser una expresión Python válida: en su lugar, se puede usar una representación más conveniente o concisa. El valor de retorno debe ser un objeto de cadena.

jfs
fuente
Esta opción es útil para imprimir cadenas concatenadas con el contenido del objeto:print "DEBUG: object value: " + repr(obj)
AlejandroVD
17

Podría valer la pena echarle un vistazo --

¿Hay un Python equivalente a Perl's Data :: Dumper?

Mi recomendación es esta:

https://gist.github.com/1071857

Tenga en cuenta que perl tiene un módulo llamado Data :: Dumper que traduce los datos del objeto nuevamente al código fuente de perl (NB: NO traduce el código nuevamente a la fuente, y casi siempre no desea que las funciones del método del objeto en la salida). Esto puede usarse para la persistencia, pero el propósito común es la depuración.

Hay una serie de cosas que el pprint estándar de Python no logra, en particular, simplemente deja de descender cuando ve una instancia de un objeto y le da el puntero hexadecimal interno del objeto (errr, ese puntero no es muy utilizado por la manera). En pocas palabras, python tiene que ver con este gran paradigma orientado a objetos, pero las herramientas que obtiene de la caja están diseñadas para trabajar con algo que no sean objetos.

El perl Data :: Dumper le permite controlar qué tan profundo quiere llegar, y también detecta estructuras enlazadas circulares (eso es realmente importante). Este proceso es fundamentalmente más fácil de lograr en perl porque los objetos no tienen magia particular más allá de su bendición (un proceso universalmente bien definido).

Tel
fuente
¡Esto debería ser un pip y un deb no solo una esencia!
phobie
2
> En pocas palabras, python tiene que ver con este gran paradigma orientado a objetos, pero las herramientas que obtiene de la caja están diseñadas para trabajar con algo que no sean objetos ... Toda una afirmación cuando el único ejemplo que está brindando es un módulo de importancia secundaria.
memeplex
@memeplex, ¿dónde dice que python se trata de OOP?
Peter Wood
Ok, solo dice que se trata de esta gran OOP, mi mal.
memeplex
13

Recomiendo usar 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
fuente
Oh, hombre, +100500
Kirby
12

En la mayoría de los casos, usar __dict__o dir()le proporcionará la información que desea. Si necesita más detalles, la biblioteca estándar incluye el módulo de inspección , que le permite obtener una cantidad impresionante de detalles. Algunos de los detalles más reales de información incluyen:

  • nombres de parámetros de función y método
  • jerarquías de clase
  • código fuente de la implementación de funciones / objetos de clase
  • variables locales fuera de un objeto frame

Si solo está buscando "¿qué valores de atributo tiene mi objeto?", Entonces dir()y __dict__probablemente sean suficientes. Si realmente está buscando profundizar en el estado actual de los objetos arbitrarios (teniendo en cuenta que en Python casi todo es un objeto), entonces inspectes digno de consideración.

William McVey
fuente
Usó su explicación en inspeccionar para mejorar la respuesta más completa. Espero que estés bien contigo.
Fernando César
10

¿Existe una función incorporada para imprimir todas las propiedades y valores actuales de un objeto?

No. La respuesta más votada excluye algunos tipos de atributos, y la respuesta aceptada muestra cómo obtener todos los atributos, incluidos los métodos y partes de la API no pública. Pero no hay una buena completa incorporado la función de este.

Entonces, el corto corolario es que puede escribir el suyo propio, pero calculará las propiedades y otros descriptores de datos calculados que son parte de la API pública, y es posible que no desee eso:

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))

Problemas con otras respuestas

Observe la aplicación de la respuesta más votada actualmente en una clase con muchos tipos diferentes de miembros de datos:

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))

solo impresiones:

{'baz': 'baz'}

Porque vars solo devuelve el __dict__de un objeto, y no es una copia, por lo que si modifica el dict devuelto por vars, también está modificando el __dict__del objeto en sí.

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

devoluciones:

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

- lo cual es malo porque quux es una propiedad que no deberíamos configurar y no deberíamos estar en el espacio de nombres ...

Aplicar el consejo en la respuesta actualmente aceptada (y otras) no es mucho mejor:

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

Como podemos ver, dirsolo devuelve todos (en realidad solo la mayoría) de los nombres asociados con un objeto.

inspect.getmembers, mencionado en los comentarios, tiene fallas similares: devuelve todos los nombres y valores.

De clase

Cuando enseño, mis alumnos crean una función que proporciona la API semánticamente pública de un objeto:

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

Podemos extender esto para proporcionar una copia del espacio de nombres semántico de un objeto, pero debemos excluir los __slots__que no están asignados, y si nos tomamos en serio la solicitud de "propiedades actuales", debemos excluir las propiedades calculadas (como podrían volverse caros y podrían interpretarse como no "actuales"):

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)}

Y ahora no calculamos ni mostramos la propiedad, quux:

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

Advertencias

Pero quizás sabemos que nuestras propiedades no son caras. Es posible que queramos alterar la lógica para incluirlos también. Y tal vez queremos excluir otros descriptores de datos personalizados .

Entonces necesitamos personalizar aún más esta función. Y entonces tiene sentido que no podamos tener una función incorporada que mágicamente sepa exactamente lo que queremos y lo proporcione. Esta es la funcionalidad que necesitamos para crearnos.

Conclusión

No hay una función integrada que haga esto, y debe hacer lo que sea más semánticamente apropiado para su situación.

Aaron Hall
fuente
Hay un paréntesis cercano adicional después FunctionType. Pero muy útil, ¡gracias!
nealmcb
@nealmcb gracias Creo que lo tengo. ¡Contento de estar en servicio! :)
Aaron Hall
7

Un ejemplo de metaprogramación Volcar objeto con magia :

$ 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

Sin argumentos:

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

Con 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>

Está un poco anticuado pero sigue funcionando.

jfs
fuente
6

Si está utilizando esto para la depuración, y solo desea un volcado recursivo de todo, la respuesta aceptada es insatisfactoria porque requiere que sus clases ya tengan buenas __str__implementaciones. Si ese no es el caso, esto funciona mucho mejor:

import json
print(json.dumps(YOUR_OBJECT, 
                 default=lambda obj: vars(obj),
                 indent=1))
Adam Cath
fuente
esto no funcionó en python 3. Tuve que instalar pymongo y hacerlo según la respuesta de @Clark
Tim Ogilvy
como con muchas de las otras respuestas aquíTypeError: vars() argument must have __dict__ attribute
robe el
6

Prueba 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)

Salida:

__main__.A(_p = 8, foo = [0, 1, ..., 8, 9], s = 5)
Symon
fuente
exactamente lo que estaba buscando para la depuración rápida :), gran descubrimiento!
Joseph Astrahan
pequeña pista agrega profundidad = 6 (o lo que necesites) como uno de los parámetros para ello y los detalles de recursividad pueden ir más allá :). Una de las cosas que me gustan de cómo imprime las listas es que muestra las primeras 2 entradas y las últimas 2 entradas para que sepa que está funcionando
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
fuente
4

Esto imprime todo el contenido del objeto de forma recursiva en formato sangrado json o 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
fuente
4

He votado a favor la respuesta que menciona solo pprint. Para ser claros, si desea ver todos los valores en una estructura de datos compleja, haga algo como:

from pprint import pprint
pprint(my_var)

Donde my_var es tu variable de interés. Cuando lo usé pprint(vars(my_var))no obtuve nada, y otras respuestas aquí no ayudaron o el método parecía innecesariamente largo. Por cierto, en mi caso particular, el código que estaba inspeccionando tenía un diccionario de diccionarios.

Vale la pena señalar que con algunas clases personalizadas puede terminar con una inútil <someobject.ExampleClass object at 0x7f739267f400> tipo de salida . En ese caso, es posible que deba implementar un __str__método o probar algunas de las otras soluciones. Todavía me gustaría encontrar algo simple que funcione en todos los escenarios, sin bibliotecas de terceros.

Nagev
fuente
3
> con algunas clases personalizadas ... Por eso no soy fanático de Python. Las cosas "a veces" funcionan y "a veces" no
AlxVallejo
3

Necesitaba imprimir información de DEPURACIÓN en algunos registros y no pude usar pprint porque la rompería. En cambio, hice esto y obtuve prácticamente lo mismo.

DO = DemoObject()

itemDir = DO.__dict__

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

Para volcar "myObject":

from bson import json_util
import json

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

Probé vars () y dir (); ambos fallaron por lo que estaba buscando. vars () no funcionó porque el objeto no tenía __dict__ (excepciones.TypeError: el argumento vars () debe tener el atributo __dict__). dir () no era lo que estaba buscando: es solo una lista de nombres de campo, no da los valores o la estructura del objeto.

Creo que json.dumps () funcionaría para la mayoría de los objetos sin default = json_util.default, pero tenía un campo de fecha y hora en el objeto, por lo que el serializador json estándar falló. Consulte ¿Cómo superar "datetime.datetime no JSON serializable" en python?

Clark
fuente
Ok, sí, tuve que instalar Pymongo aunque para usarlo.
Tim Ogilvy
3

¿Por qué no algo simple?

for key,value in obj.__dict__.iteritems():
    print key,value
Michael Thamm
fuente
¿No debería ser eso for key,value in obj.__dict__.iteritems(): print key,value?
Raz
2

pprint contiene una "bonita impresora" para producir representaciones estéticamente agradables de sus estructuras de datos. El formateador produce representaciones de estructuras de datos que el intérprete puede analizar correctamente, y también son fáciles de leer para un humano. La salida se mantiene en una sola línea, si es posible, y se sangra cuando se divide en varias líneas.

shahjapan
fuente
2

Solo prueba beeprint .

Le ayudará no solo a imprimir variables de objeto, sino también a una salida hermosa, como esta:

class(NormalClassNewStyle):
  dicts: {
  },
  lists: [],
  static_props: 1,
  tupl: (1, 2)
Anyany Pan
fuente
1
Parece que este módulo ya no se mantiene y tiene varios problemas abiertos. En lugar de usar ppretty
Wavesailor
1

Para todos los que luchan con

  • vars() No devuelve todos los atributos.
  • dir() no devuelve los valores de los atributos.

El siguiente código imprime todos los atributos de objcon sus valores:

for attr in dir(obj):
        try:
            print("obj.{} = {}".format(attr, getattr(obj, attr)))
        except AttributeError:
            print("obj.{} = ?".format(attr))
Robert Hönig
fuente
no recibe errores, pero no es recursivo, así que solo obtenga muchas direcciones hexadecimales
robe el
0

Puede probar la barra de herramientas de depuración de frascos.
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
fuente
0

Me gusta trabajar con claves o valores de tipos integrados de objetos de Python .

Para los atributos independientemente de que sean métodos o variables:

o.keys()

Para valores de esos atributos:

o.values()
Evhz
fuente
0

Esto funciona sin importar cómo se definan sus variables dentro de una clase, dentro de __init__ o afuera.

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