Is there a built-in function to print all the current properties and values of an object?

1,112,080

Solution 1

You want vars() mixed with pprint():

from pprint import pprint
pprint(vars(your_object))

Solution 2

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

There are many 3rd-party functions out there that add things like exception handling, national/special character printing, recursing into nested objects etc. according to their authors' preferences. But they all basically boil down to this.

Solution 3

dir has been mentioned, but that'll only give you the attributes' names. If you want their values as well try __dict__.

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

o = O()

Here is the output:

>>> o.__dict__

{'value': 3}

Solution 4

Is there a built-in function to print all the current properties and values of an object?

No. The most upvoted answer excludes some kinds of attributes, and the accepted answer shows how to get all attributes, including methods and parts of the non-public api. But there is no good complete builtin function for this.

So the short corollary is that you can write your own, but it will calculate properties and other calculated data-descriptors that are part of the public API, and you might not want that:

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

Problems with other answers

Observe the application of the currently top voted answer on a class with a lot of different kinds of data members:

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

only prints:

{'baz': 'baz'}

Because vars only returns the __dict__ of an object, and it's not a copy, so if you modify the dict returned by vars, you're also modifying the __dict__ of the object itself.

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

returns:

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

-- which is bad because quux is a property that we shouldn't be setting and shouldn't be in the namespace...

Applying the advice in the currently accepted answer (and others) is not much better:

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

As we can see, dir only returns all (actually just most) of the names associated with an object.

inspect.getmembers, mentioned in the comments, is similarly flawed - it returns all names and values.

From class

When teaching I have my students create a function that provides the semantically public API of an object:

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

We can extend this to provide a copy of the semantic namespace of an object, but we need to exclude __slots__ that aren't assigned, and if we're taking the request for "current properties" seriously, we need to exclude calculated properties (as they could become expensive, and could be interpreted as not "current"):

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

And now we do not calculate or show the property, quux:

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

Caveats

But perhaps we do know our properties aren't expensive. We may want to alter the logic to include them as well. And perhaps we want to exclude other custom data descriptors instead.

Then we need to further customize this function. And so it makes sense that we cannot have a built-in function that magically knows exactly what we want and provides it. This is functionality we need to create ourselves.

Conclusion

There is no built-in function that does this, and you should do what is most semantically appropriate for your situation.

Solution 5

You can use the "dir()" function to do this.

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

Another useful feature is help.

>>> 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
Share:
1,112,080
fuentesjr
Author by

fuentesjr

🤡

Updated on January 18, 2022

Comments

  • fuentesjr
    fuentesjr over 2 years

    So what I'm looking for here is something like PHP's print_r function.

    This is so I can debug my scripts by seeing what's the state of the object in question.

  • Admin
    Admin over 15 years
    unpythonic, because follows not-invented-here
  • Dan Lenski
    Dan Lenski over 15 years
    Say what? Sure, you can use the getmembers() function in the standard inspect module, but I thought this would be more useful in that it illustrates how to do introspection in general.
  • Admin
    Admin over 15 years
    even then it sets a bad example, because you essentially reemplemented obj.__dict__ .
  • Dan Lenski
    Dan Lenski over 15 years
    NOT AT ALL. dir(obj) shows properties that aren't found in __dict__ (such as __doc__ and __module__). Furthermore, __dict__ doesn't work at all for objects declared with __slots__. In general, __dict__ shows user-level properties that are actually stored in a dictionary internally. dir() shows more.
  • Admin
    Admin over 15 years
    what are you talking about? both __module__ and __doc__ are in __dict__!
  • Admin
    Admin over 12 years
    vars() simply returns the __dict__ of its argument and that is also the fallback of dir() in case there is no __dir__ method. so use dir() in the first place, as i said.
  • hobs
    hobs over 12 years
    Some classes/objects don't contain any __dict__ attribute/member. I know it's crazy, but true. Built-ins like int and str or re.MatchObjects are common examples. Try 'hello'.__dict__, then try dir('hello')
  • Timmmm
    Timmmm almost 12 years
    @hop: dir() gives you all the built in things you probably don't care about like __str__ and __new__. var() doesn't.
  • sdaau
    sdaau over 10 years
    Well, this answer at least prints both attributes' names and values, in case an object doesn't have a dict (like the return from, say, QtGui.QMdiSubWindow.sizePolicy()), which is what I like about it.
  • port5432
    port5432 about 10 years
    I like the vars/pprint option above, but this is good as it does not require inclusion of an libraries.
  • Raz
    Raz over 9 years
    Shouldn't that be for key,value in obj.__dict__.iteritems(): print key,value?
  • Tim Ogilvy
    Tim Ogilvy about 9 years
    this didn't work on python 3. Had to install pymongo and do it as per @Clark 's answer
  • Tim Ogilvy
    Tim Ogilvy about 9 years
    Okay yep had to install pymongo tho to use it.
  • phobie
    phobie almost 9 years
    This should be a pip and a deb not only a gist!
  • anatoly techtonik
    anatoly techtonik almost 9 years
    This fails on sets and other objects that doesn't have __dict__ attribute.
  • anatoly techtonik
    anatoly techtonik almost 9 years
    Objects like set doesn't have __dict__, so for them it will fail with AttributeError: 'set' object has no attribute '__dict__'
  • AlejandroVD
    AlejandroVD over 8 years
    This option is useful for printing strings concatenated with the content of the object: print "DEBUG: object value: " + repr(obj)
  • memeplex
    memeplex about 8 years
    > So in a nutshell, python is all about this great object oriented paradigm, but the tools you get out of the box are designed for working with something other than objects... Quite a claim when the only example you're providing is a module of secondary importance.
  • Jordan
    Jordan almost 7 years
    LOL Tenable use this in their Nessus python library (see the objdump function) github.com/tenable/nessrest/blob/…
  • Dan Lenski
    Dan Lenski almost 7 years
    Indeed… verbatim! Wow :-D github.com/tenable/nessrest/blob/…
  • AlxVallejo
    AlxVallejo over 6 years
    >with some custom classes ... This is why I'm not a fan of python. Things "sometimes" work and "sometimes" not
  • hidefromkgb
    hidefromkgb over 6 years
    I do not care whether that`s «unpythonic» or whatnot. It gets the job done, which in debugging is the one and only thing that matters.
  • Fernando César
    Fernando César over 6 years
    Used your explanation on inspect to improve the most complete answer. Hope that's ok with you.
  • Peter Wood
    Peter Wood over 5 years
    @memeplex where does it say python is all about OOP?
  • memeplex
    memeplex over 5 years
    Ok, it just says it's all about this great OOP, my bad.
  • Wavesailor
    Wavesailor over 5 years
    This module does not seemed to be maintained any more and have a number of open issues. Rather use ppretty
  • rob
    rob over 4 years
    as with many of the other answers here TypeError: vars() argument must have __dict__ attribute
  • rob
    rob over 4 years
    get no errors, but not recursive so just get a lot of hex addresses
  • Joseph Astrahan
    Joseph Astrahan over 4 years
    exactly what I was looking for for quick debug :), great find!
  • Joseph Astrahan
    Joseph Astrahan over 4 years
    little hint add depth=6 (or however far you need) as one of the parameters for it and the recursion details can go further :). One of the things I like about how it prints lists is it shows the first 2 entires and last 2 entries so you know it's working
  • Rainb
    Rainb about 4 years
    this is only for 2.7
  • Basil Musa
    Basil Musa almost 4 years
    The best answer so far. To hell with "unpythonic" approaches : )))
  • joe-khoa
    joe-khoa over 3 years
    this is absolutely good anwers, adding more: from inspect import getmembers
  • cowlinator
    cowlinator over 3 years
    @hop, vars() gives the values of the fields, while dir() leaves them a mystery.
  • Sion C
    Sion C almost 3 years
    str(pformat(vars(session)).encode('utf-8')).replace('\\n', '\n').replace('\\t', '\t') - dont kill me but with utf8 that what works
  • NZD
    NZD almost 3 years
    pypi.org/project/beeprint (or github.com/panyanyany/beeprint) pretty prints 'everything' and also recursively.
  • Smart Manoj
    Smart Manoj almost 3 years
    that what for parameters to get customized thing from a function
  • Smart Manoj
    Smart Manoj almost 3 years
    @NZD not works for from collections import * ; obj=Counter([3,4])
  • Vladimir
    Vladimir over 2 years
    Addition to exclude all built-in vars (methods, functions etc) : {attr: getattr(your_obj, attr) for attr in dir(your_obj) and "__" not in attr}
  • ejkitchen
    ejkitchen over 2 years
    This is the most comprehensive answer and should be upvoted more
  • TCSGrad
    TCSGrad over 2 years
    Holy eff, THIS is the answer i was looking for. Why it isnt the accepted answer, i'll never know.
  • Admin
    Admin about 2 years
    Nice, suited. But fixed compile errors (maybe, other Python version) for key, value in params.__dict__.items(): print(key + " = " + str(value))