Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python pretty print nested objects

I have 3 python classes A, B and C. A contains B object and B contains C's object. What I want is when I print A class object, it should pretty print in the below format. There can be more nesting also inside C class.

A:
    loc : XYZ
    qual : ABC
    b :
        name : ABC
        age : 30
        c :
            address : ABC
            phn : 99009

Below are the classes for reference.

class C(object):
    def __init__(self):
        self.address='ABC'
        self.phn=99009

class B(object):
    def __init__(self):
        self.name='ABC'
        self.age=30
        self.c = C()

class A(object):
    def __init__(self):
        self.loc = 'XYZ'
        self.qual = 'ABC'
        self.b = B()
like image 406
dks551 Avatar asked Aug 08 '18 19:08

dks551


People also ask

How do I print a nested object in Python?

The simplest thing to do is to create a custom PrettyPrinter subclass that overrides the methods documented there, so it handles your objects as "recursive objects" like lists and dicts. Then you just use an instance of that class in place of the pprint module.

Why do we use Pprint?

The pprint module provides a capability to “pretty-print” arbitrary Python data structures in a form which can be used as input to the interpreter. If the formatted structures include objects which are not fundamental Python types, the representation may not be loadable.

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

Use Python's vars() to Print an Object's Attributes The dir() function, as shown above, prints all of the attributes of a Python object.


2 Answers

The following works by letting your classes inherit from a common base class implementing the __str__ method:

class PrettyPrinter(object):
    def __str__(self):
        lines = [self.__class__.__name__ + ':']
        for key, val in vars(self).items():
            lines += '{}: {}'.format(key, val).split('\n')
        return '\n    '.join(lines)

class C(PrettyPrinter):
    def __init__(self):
        self.address='ABC'
        self.phn=99009

class B(PrettyPrinter):
    def __init__(self):
        self.name='ABC'
        self.age=30
        self.c = C()

class A(PrettyPrinter):
    def __init__(self):
        self.loc = 'XYZ'
        self.qual = 'ABC'
        self.b = B()

a = A()
print(a)

In Python 3.6 and newer, this displays like

A:
    loc: XYZ
    qual: ABC
    b: B:
        name: ABC
        age: 30
        c: C:
            address: ABC
            phn: 99009

Note that all attributes are automatically printed. Their print order is determined by the vars function, which really looks in the __dict__ dictionary. This dictionary has a nondeterministic order in Python 3.5 and below, and so the printout is not nearly as nice as in 3.6 and up.

like image 62
jmd_dk Avatar answered Oct 19 '22 17:10

jmd_dk


The following recursive funciton works from scratch using the __dict__ attr. of the classes to get key:value pairs of the class' attributes. From here, we just test if the value is another class (in which case we call ourselves again), otherwise we simply print it in your desired format.

The only other thing to keep track of is the current indent of what level this line is currently printing at. This can be easily done with a default parameter (indent) that we increment before each recursion.

def pretty_print(clas, indent=0):
    print(' ' * indent +  type(clas).__name__ +  ':')
    indent += 4
    for k,v in clas.__dict__.items():
        if '__dict__' in dir(v):
            pretty_print(v,indent)
        else:
            print(' ' * indent +  k + ': ' + str(v))

and it works:

>>> pretty_print(A())
A:
    loc: XYZ
    qual: ABC
    B:
        name: ABC
        age: 30
        C:
            address: ABC
            phn: 99009
like image 6
Joe Iddon Avatar answered Oct 19 '22 16:10

Joe Iddon