Esiste una funzione integrata per stampare tutte le proprietà e i valori correnti di un oggetto?


Risposte:


591

Stai davvero mescolando insieme due cose diverse.

Usa dir(), vars()o il inspectmodulo per ottenere ciò che ti interessa (io uso __builtins__come esempio; puoi invece usare qualsiasi oggetto).

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

Stampa quel dizionario come preferisci:

>>> 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 stampa graziosa è disponibile anche nel debugger interattivo come 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__'}

28
Sorprendentemente, sembra che non tutti gli oggetti abbiano un __dict__membro (uno re.MatchObjectper esempio), ma builtin dir()funziona per tutti gli oggetti.
Piani cottura

print re.compile(r'slots').search('No slots here either.').__slots__
Piani cottura

3
Uno nuovo per me. Grazie. Il punto ha innescato il parser di percorso del modulo del mio cervello. Mai nemmeno considerato il "modulo" latino.
Piani cottura

4
perché non parli di più del inspectmodulo nella tua risposta? Penso che sia la cosa più vicina a print_r o var_dump.
Hai Phaikawl,

1
Come si accede quindi ai valori dietro gli attributi elencati da dir()? dir()restituisce solo un elenco di nomi e non tutti quelli presenti nell'attributo vars()o __dict__.
Ciao Arrivederci

981

Vuoi vars()mescolato con pprint():

from pprint import pprint
pprint(vars(your_object))

24
vars()restituisce semplicemente il __dict__suo argomento e questo è anche il fallback dir()nel caso in cui non vi sia alcun __dir__metodo. quindi utilizzare dir()in primo luogo, come ho detto.

28
@hop: dir()ti dà tutte le cose integrate che probabilmente non ti interessano __str__e __new__. var()non lo fa.
Timmmm,

14
Questo non riesce su set e altri oggetti che non hanno __dict__attributo.
Anatoly Techtonik,

209
def dump(obj):
  for attr in dir(obj):
    print("obj.%s = %r" % (attr, getattr(obj, attr)))

Esistono molte funzioni di terze parti che aggiungono cose come la gestione delle eccezioni, la stampa di caratteri nazionali / speciali, il ricorrere in oggetti nidificati ecc. In base alle preferenze dei loro autori. Ma sostanzialmente si riducono a questo.


5
unpythonic, perché segue non inventato-qui

14
Che cosa? Certo, puoi usare la getmembers()funzione nel inspectmodulo standard , ma ho pensato che sarebbe stato più utile in quanto illustra come fare l'introspezione in generale.
Dan Lenski,

20
AFFATTO. dir (obj) mostra le proprietà che non sono state trovate in __dict__(come __doc__e __module__). Inoltre, __dict__non funziona affatto per gli oggetti dichiarati con __slots__. In generale, __dict__mostra le proprietà a livello di utente che sono effettivamente archiviate in un dizionario internamente. dir () mostra di più.
Dan Lenski,

8
Alcune classi / oggetti non contengono alcun __dict__attributo / membro. So che è pazzo, ma vero. Built-in come inte stro re.MatchObjects sono esempi comuni. Prova 'hello'.__dict__, poi provadir('hello')
piani cottura

11
Non m'interessa se questo è «non meccanico» o quant'altro. Fa il lavoro, che nel debug è l'unica e l'unica cosa che conta.
hidefromkgb,

59

dir è stato menzionato, ma questo ti darà solo i nomi degli attributi. Se vuoi anche i loro valori, prova __dict__.

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

o = O()

Ecco l'output:

>>> o.__dict__

{'value': 3}

9
Oggetti come setnon hanno __dict__, quindi per loro falliràAttributeError: 'set' object has no attribute '__dict__'
anatoly techtonik il

23

È possibile utilizzare la funzione "dir ()" per fare ciò.

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

Un'altra utile funzione è l'aiuto.

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

22

Per stampare lo stato corrente dell'oggetto è possibile:

>>> obj # in an interpreter

o

print repr(obj) # in a script

o

print obj

Per le tue classi definisci __str__o __repr__metodi. Dalla documentazione di Python :

__repr__(self)Chiamato dalla repr()funzione integrata e dalle conversioni di stringa (virgolette inverse) per calcolare la rappresentazione di stringa "ufficiale" di un oggetto. Se possibile, ciò dovrebbe apparire come un'espressione Python valida che potrebbe essere utilizzata per ricreare un oggetto con lo stesso valore (dato un ambiente appropriato). Se ciò non è possibile, dovrebbe essere restituita una stringa del modulo "<... qualche descrizione utile ...>". Il valore restituito deve essere un oggetto stringa. Se una classe definisce repr () ma non __str__(), __repr__()viene utilizzata anche quando è richiesta una rappresentazione di stringa "informale" delle istanze di quella classe. Questo è in genere utilizzato per il debug, quindi è importante che la rappresentazione sia ricca di informazioni e non ambigua.

__str__(self)Chiamato dalla str()funzione integrata e dall'istruzione print per calcolare la rappresentazione di stringa "informale" di un oggetto. Ciò differisce dal fatto __repr__()che non deve essere un'espressione Python valida: al suo posto è possibile utilizzare una rappresentazione più comoda o concisa. Il valore restituito deve essere un oggetto stringa.


Questa opzione è utile per la stampa di stringhe concatenate con il contenuto dell'oggetto:print "DEBUG: object value: " + repr(obj)
AlejandroVD

17

Potrebbe valere la pena di provarlo --

Esiste un Python equivalente a Data :: Dumper di Perl?

La mia raccomandazione è questa:

https://gist.github.com/1071857

Si noti che perl ha un modulo chiamato Data :: Dumper che traduce i dati degli oggetti in codice sorgente perl (NB: NON traduce il codice in sorgente e quasi sempre non si desidera che il metodo dell'oggetto funzioni nell'output). Questo può essere usato per la persistenza, ma lo scopo comune è il debug.

Ci sono una serie di cose che la pprint python standard non riesce a raggiungere, in particolare smette di scendere quando vede un'istanza di un oggetto e ti dà il puntatore esadecimale interno dell'oggetto (errr, quel puntatore non è molto utile per la via). Quindi, in poche parole, Python è incentrato su questo grande paradigma orientato agli oggetti, ma gli strumenti che ottieni fuori dalla scatola sono progettati per lavorare con qualcosa di diverso dagli oggetti.

Il perl Data :: Dumper ti consente di controllare quanto in profondità vuoi andare, e rileva anche strutture collegate circolari (questo è davvero importante). Questo processo è fondamentalmente più facile da realizzare in perl perché gli oggetti non hanno una magia particolare oltre la loro benedizione (un processo universalmente ben definito).


Questo dovrebbe essere un pip e un deb non solo un senso!
phobie,

2
> Quindi, in poche parole, Python è tutto incentrato su questo fantastico paradigma orientato agli oggetti, ma gli strumenti che ottieni fuori dagli schemi sono progettati per lavorare con qualcosa di diverso dagli oggetti ... Una vera affermazione quando l'unico esempio che stai fornendo è un modulo di importanza secondaria.
memeplex

@memeplex dove dice python è tutto su OOP?
Peter Wood,

Ok, dice solo che si tratta di questo fantastico OOP, mio ​​cattivo.
memeplex,

13

Raccomando di usare 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__.

Oh, amico, +100500
Kirby,

12

Nella maggior parte dei casi, utilizzando __dict__o dir()otterrai le informazioni desiderate. Se dovessi avere bisogno di maggiori dettagli, la libreria standard include il modulo inspect , che ti consente di ottenere una quantità impressionante di dettagli. Alcuni dei veri nuggest di informazioni includono:

  • nomi di parametri di funzione e metodo
  • gerarchie di classi
  • codice sorgente dell'implementazione di oggetti funzioni / classe
  • variabili locali da un oggetto frame

Se stai solo cercando "quali valori di attributo ha il mio oggetto?", Allora dir()e __dict__probabilmente sono sufficienti. Se stai davvero cercando di scavare nello stato attuale di oggetti arbitrari (tenendo presente che in Python quasi tutto è un oggetto), allora inspectè degno di considerazione.


Hai usato la tua spiegazione su inspect per migliorare la risposta più completa. Spero che vada bene per te.
Fernando César,

10

Esiste una funzione integrata per stampare tutte le proprietà e i valori correnti di un oggetto?

No. La risposta più votata esclude alcuni tipi di attributi e la risposta accettata mostra come ottenere tutti gli attributi, inclusi metodi e parti dell'API non pubblico. Ma non c'è bene completo incorporato la funzione di questo.

Quindi il corollario breve è che puoi scrivere il tuo, ma calcolerà proprietà e altri descrittori di dati calcolati che fanno parte dell'API pubblica e potresti non volerlo:

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

Problemi con altre risposte

Osserva l'applicazione della risposta attualmente più votata su una classe con molti tipi diversi di membri dei dati:

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

stampa solo:

{'baz': 'baz'}

Perché restituisce vars solo l' __dict__oggetto di, e non è una copia, quindi se si modifica il dict restituito da Vars, si sta anche modificando __dict__l'oggetto stesso.

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

ritorna:

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

- il che è negativo perché quux è una proprietà che non dovremmo impostare e non dovrebbe essere nello spazio dei nomi ...

Applicare i consigli nella risposta attualmente accettata (e altri) non è molto meglio:

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

Come possiamo vedere, dirrestituisce solo tutto (in realtà solo la maggior parte) dei nomi associati a un oggetto.

inspect.getmembers, menzionato nei commenti, è ugualmente imperfetto: restituisce tutti i nomi e i valori.

Dalla classe

Quando insegno, i miei studenti creano una funzione che fornisce l'API semanticamente pubblica di un oggetto:

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

Possiamo estenderlo per fornire una copia dello spazio dei nomi semantico di un oggetto, ma dobbiamo escludere quelli __slots__che non sono assegnati e se prendiamo sul serio la richiesta di "proprietà correnti", dobbiamo escludere le proprietà calcolate (come potrebbero diventare costosi e potrebbero essere interpretati come non "attuali"):

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

E ora non calcoliamo o mostriamo la proprietà, quux:

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

Avvertenze

Ma forse sappiamo che le nostre proprietà non sono costose. Potremmo voler modificare la logica anche per includerli. E forse vogliamo invece escludere altri descrittori di dati personalizzati .

Quindi dobbiamo personalizzare ulteriormente questa funzione. E quindi ha senso che non possiamo avere una funzione integrata che magicamente sa esattamente cosa vogliamo e lo fornisce. Questa è la funzionalità che dobbiamo creare noi stessi.

Conclusione

Non esiste una funzione integrata che lo faccia e dovresti fare ciò che è semanticamente più appropriato per la tua situazione.


Dopo c'è una parentesi molto stretta FunctionType. Ma molto utile - grazie!
nealmcb,

@nealmcb grazie penso di averlo capito. Sono contento di essere al servizio! :)
Aaron Hall

7

Un esempio di metaprogrammazione Scarica oggetto 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

Senza argomenti:

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

È un po 'datato ma funziona ancora.


6

Se lo stai usando per il debug e vuoi solo un dump ricorsivo di tutto, la risposta accettata non è soddisfacente perché richiede che le tue classi abbiano __str__già buone implementazioni. In caso contrario, funziona molto meglio:

import json
print(json.dumps(YOUR_OBJECT, 
                 default=lambda obj: vars(obj),
                 indent=1))

questo non ha funzionato su Python 3. Ho dovuto installare Pymongo e farlo secondo la risposta di @Clark
Tim Ogilvy

come con molte delle altre risposte quiTypeError: vars() argument must have __dict__ attribute
rubare

6

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

Produzione:

__main__.A(_p = 8, foo = [0, 1, ..., 8, 9], s = 5)

esattamente quello che stavo cercando per il debug rapido :), ottima scoperta!
Joseph Astrahan,

piccolo suggerimento aggiungere depth = 6 (o comunque lontano è necessario) come uno dei parametri per esso e i dettagli di ricorsione possono andare oltre :). Una delle cose che mi piace di come stampa gli elenchi è che mostra i primi 2 impegni e le ultime 2 voci in modo che tu sappia che funziona
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))

4

Questo stampa ricorsivamente tutto il contenuto dell'oggetto in formato rientrato 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)

4

Ho votato a favore della risposta che menziona solo la pprint. Per essere chiari, se vuoi vedere tutti i valori in una struttura di dati complessa, fai qualcosa del tipo:

from pprint import pprint
pprint(my_var)

Dove my_var è la variabile di interesse. Quando ho usato non pprint(vars(my_var))ho ottenuto nulla e altre risposte qui non sono state di aiuto o il metodo sembrava inutilmente lungo. A proposito, nel mio caso particolare, il codice che stavo ispezionando aveva un dizionario di dizionari.

Vale la pena sottolineare che con alcune classi personalizzate potresti finire con un <someobject.ExampleClass object at 0x7f739267f400>tipo di output inutile . In tal caso, potrebbe essere necessario implementare un __str__metodo o provare alcune delle altre soluzioni. Mi piacerebbe ancora trovare qualcosa di semplice che funzioni in tutti gli scenari, senza librerie di terze parti.


3
> con alcune classi personalizzate ... Ecco perché non sono un fan di Python. Le cose "a volte" funzionano e "a volte" no
AlxVallejo,

3

Avevo bisogno di stampare le informazioni di DEBUG in alcuni registri e non ero in grado di usare pprint perché si sarebbe rotto. Invece l'ho fatto e ho praticamente ottenuto la stessa cosa.

DO = DemoObject()

itemDir = DO.__dict__

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

3

Per scaricare "myObject":

from bson import json_util
import json

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

Ho provato vars () e dir (); entrambi hanno fallito per quello che stavo cercando. vars () non ha funzionato perché l'oggetto non aveva __dict__ (exceptions.TypeError: l'argomento vars () deve avere l'attributo __dict__). dir () non era quello che cercavo: è solo un elenco di nomi di campi, non fornisce i valori o la struttura dell'oggetto.

Penso che json.dumps () funzionerebbe per la maggior parte degli oggetti senza default = json_util.default, ma avevo un campo datetime nell'oggetto, quindi il serializzatore json standard non è riuscito. Vedi Come superare "datetime.datetime non JSON serializzabile" in Python?


Okay, ho dovuto installare Pymongo per usarlo.
Tim Ogilvy,

3

Perché non qualcosa di semplice:

for key,value in obj.__dict__.iteritems():
    print key,value

Non dovrebbe essere for key,value in obj.__dict__.iteritems(): print key,value?
Raz,

2

pprint contiene una "bella stampante" per produrre rappresentazioni esteticamente gradevoli delle tue strutture dati. Il formatter produce rappresentazioni di strutture di dati che possono essere analizzate correttamente dall'interprete e sono anche facili da leggere per un essere umano. L'output viene mantenuto su una sola riga, se possibile, e indentato quando suddiviso su più righe.


2

Prova a essere beeprint .

Ti aiuterà non solo con la stampa delle variabili degli oggetti, ma anche con un bellissimo output, come questo:

class(NormalClassNewStyle):
  dicts: {
  },
  lists: [],
  static_props: 1,
  tupl: (1, 2)

1
Questo modulo non sembra più essere mantenuto e presenta una serie di problemi aperti. Piuttosto usa ppretty
Wavesailor il

1

Per tutti coloro che lottano con

  • vars() non restituendo tutti gli attributi.
  • dir() non restituendo i valori degli attributi.

Il codice seguente stampa tutti gli attributi di objcon i loro valori:

for attr in dir(obj):
        try:
            print("obj.{} = {}".format(attr, getattr(obj, attr)))
        except AttributeError:
            print("obj.{} = ?".format(attr))

non ottenere errori, ma non ricorsivi, quindi prendi un sacco di indirizzi esadecimali
ruba l'

0

Puoi provare la barra di debug di 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)

0

Mi piace lavorare con chiavi o valori di tipi incorporati nell'oggetto python .

Per gli attributi, indipendentemente dal fatto che siano metodi o variabili:

o.keys()

Per i valori di tali attributi:

o.values()

0

Funziona indipendentemente dal modo in cui le variabili sono definite all'interno di una classe, all'interno di __init__ o all'esterno.

your_obj = YourObj()
attrs_with_value = {attr: getattr(your_obj, attr) for attr in dir(your_obj)}
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.