Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I recursively print the contents of a variable, including both the data and object attributes?

str() and repr() can be used to print the contents of a variable in python. But the contents of a variable may be quite complex. The pprint library, reported as the php var_dump() equivalent, works nicely for displaying just data in an easy to read format: What is a Python equivalent of PHP's var_dump()?, Is there a function in Python to print all the current properties and values of an object?

However if there are objects in the data ([edit] that haven't implemented __str__ or __repr__), str(), repr() and pprint just gives their names. I'd like a method that can recursively walk through objects' attributes too, properly giving the entire representation of a variable.

Certain functions such as builtins shouldn't be printed as it's not useful. The method should also be able to handle issues such as getattr throwing exceptions. Perhaps custom iterables could also be handled the same way as lists.


I've given it a shot below. Not that it doesn't work, but I'm sure there are edge cases not accounted for and probably some missing information from the output (e.g. distinguish tuples/lists). What I mean to say is, please share alternatives :)

like image 728
jozxyqk Avatar asked Aug 29 '14 12:08

jozxyqk


People also ask

How do you print all attributes of an object in Python?

To print the attributes of an object we can use “object. __dict__” and it return a dictionary of all names and attributes of object.

How do you print a variable type in Python?

How to Print the Type of a Variable in Python. To get the type of a variable in Python, you can use the built-in type() function. In Python, everything is an object. So, when you use the type() function to print the type of the value stored in a variable to the console, it returns the class type of the object.

How do you get data from an object in Python?

Python getattr() function. Python getattr() function is used to get the value of an object's attribute and if no attribute of that object is found, default value is returned. Basically, returning the default value is the main reason why you may need to use Python getattr() function.


2 Answers

This prints out all the object contents recursively in json or yaml (take your pick) indented format:

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

serialized = jsonpickle.encode(obj)
print json.dumps(json.loads(serialized), indent=4)
print yaml.dump(yaml.load(serialized), indent=4)
like image 98
wisbucky Avatar answered Oct 16 '22 11:10

wisbucky


Here's my answer. This works pretty well for my purposes, but again, I'm sure there are more robust ways to do this. If you have a better way, please share it :)

import types
def var_dump(obj, depth=4, l=""):
    #fall back to repr
    if depth<0: return repr(obj)
    #expand/recurse dict
    if isinstance(obj, dict):
        name = ""
        objdict = obj
    else:
        #if basic type, or list thereof, just print
        canprint=lambda o:isinstance(o, (int, float, str, unicode, bool, types.NoneType, types.LambdaType))
        try:
            if canprint(obj) or sum(not canprint(o) for o in obj) == 0: return repr(obj)
        except TypeError, e:
            pass
        #try to iterate as if obj were a list
        try:
            return "[\n" + "\n".join(l + var_dump(k, depth=depth-1, l=l+"  ") + "," for k in obj) + "\n" + l + "]"
        except TypeError, e:
            #else, expand/recurse object attribs
            name = (hasattr(obj, '__class__') and obj.__class__.__name__ or type(obj).__name__)
            objdict = {}
            for a in dir(obj):
                if a[:2] != "__" and (not hasattr(obj, a) or not hasattr(getattr(obj, a), '__call__')):
                    try: objdict[a] = getattr(obj, a)
                    except Exception, e: objdict[a] = str(e)
    return name + "{\n" + "\n".join(l + repr(k) + ": " + var_dump(v, depth=depth-1, l=l+"  ") + "," for k, v in objdict.iteritems()) + "\n" + l + "}"

Example output:

class B(object):
    mystatic = [1,2,3]  

class A:
    mystatic = "hello"
    def __init__(self):
        self.mymember1 = B()
        self.mymember2 = B(), 123.4, "world"
    def myfunc(self):
        print "hi"

var = {"foo": A(), "bar": B()}

...

>>> print var_dump(var)
{
'foo': A{
  'mystatic': 'hello',
  'mymember1': B{
    'mystatic': [1, 2, 3],
    },
  'mymember2': [
    B{
      'mystatic': [1, 2, 3],
      },
    123.4,
    'world',
    ],
  },
'bar': B{
  'mystatic': [1, 2, 3],
  },
}

I originally wrote this because django's debug toolbar used pprint and was only showing first level data.

like image 42
jozxyqk Avatar answered Oct 16 '22 12:10

jozxyqk