Pretty print namedtuple Pretty print namedtuple python python

Pretty print namedtuple


I use namedtuple's _asdict method.

However, it returns an OrderedDict which pprint won't indent, so I convert it to a dict:

>>> from collections import namedtuple>>> Busbar = namedtuple('Busbar', 'id name voltage')>>> busbar = Busbar(id=102, name='FACTORY', voltage=21.8)

With pprint and dict:

>>> from pprint import pprint>>> pprint(dict(busbar._asdict())){'id': 102, 'name': 'FACTORY', 'voltage': 21.8}


The pprint PrettyPrinter in Python 3 is much more extendable than it used to be in Python 2. You could create your own printer like below to add methods for the object you want to handle without messing too much with pprint "private" methods and attributes.

You can see an online example here: https://repl.it/HkDd/1

from io import StringIOimport pprintclass MyPrettyPrinter(pprint.PrettyPrinter):    def format_namedtuple(self, object, stream, indent, allowance, context, level):        # Code almost equal to _format_dict, see pprint code        write = stream.write        write(object.__class__.__name__ + '(')        object_dict = object._asdict()        length = len(object_dict)        if length:            # We first try to print inline, and if it is too large then we print it on multiple lines            inline_stream = StringIO()            self.format_namedtuple_items(object_dict.items(), inline_stream, indent, allowance + 1, context, level, inline=True)            max_width = self._width - indent - allowance            if len(inline_stream.getvalue()) > max_width:                self.format_namedtuple_items(object_dict.items(), stream, indent, allowance + 1, context, level, inline=False)            else:                stream.write(inline_stream.getvalue())        write(')')    def format_namedtuple_items(self, items, stream, indent, allowance, context, level, inline=False):        # Code almost equal to _format_dict_items, see pprint code        indent += self._indent_per_level        write = stream.write        last_index = len(items) - 1        if inline:            delimnl = ', '        else:            delimnl = ',\n' + ' ' * indent            write('\n' + ' ' * indent)        for i, (key, ent) in enumerate(items):            last = i == last_index            write(key + '=')            self._format(ent, stream, indent + len(key) + 2,                         allowance if last else 1,                         context, level)            if not last:                write(delimnl)    def _format(self, object, stream, indent, allowance, context, level):        # We dynamically add the types of our namedtuple and namedtuple like         # classes to the _dispatch object of pprint that maps classes to        # formatting methods        # We use a simple criteria (_asdict method) that allows us to use the        # same formatting on other classes but a more precise one is possible        if hasattr(object, '_asdict') and type(object).__repr__ not in self._dispatch:            self._dispatch[type(object).__repr__] = MyPrettyPrinter.format_namedtuple        super()._format(object, stream, indent, allowance, context, level)

and use it like so:

from collections import namedtupleSegment = namedtuple('Segment', 'p1 p2')# Your own namedtuple-like classclass Node:    def __init__(self, x, y, segments=[]):        self.x = x        self.y = y        self.segments = segments    def _asdict(self):        return {"x": self.x, "y": self.y, "segments": self.segments}    # Default repr    def __repr__(self):        return "Node(x={}, y={}, segments={})".format(self.x, self.y, self.segments)# A circular structure for the demonode = Node(0, 0)segments = [    Segment(node, Node(1, 1)),    Segment(node, Node(2, 1)),    Segment(node, Node(1, 2, segments=[      Segment(Node(2, 3), Node(1, 1)),    ])),]node.segments = segmentspp = MyPrettyPrinter(indent=2, depth=2)pp.pprint(node)

outputs

Node(  x=0,  y=0,  segments=[ Segment(                p1=<Recursion on Node with id=139778851454536>,                p2=Node(x=1, y=1, segments=[])),              Segment(                p1=<Recursion on Node with id=139778851454536>,                p2=Node(x=2, y=1, segments=[])),              Segment(                p1=<Recursion on Node with id=139778851454536>,                p2=Node(x=1, y=2, segments=[...]))])


Unlike all other solutions here, this solution is generic and works for namedtuples inside other containers as well:

import black# value_to_print can either be a namedtuple, or a container containing tuples,# or a namedtuple containing containers containing other namedtuples,# or whatever else you want.print(black.format_str(repr(value_to_print), mode=black.Mode()))

This requires installing black, which can be done via sudo pip install black.