Pretty print namedtuple - программирование

Pretty print namedtuple

Я пробовал pprint из pprint, но его вывод - только одна строка, нет многострочного вывода и отступов.

4b9b3361

Ответ 1

Я использую метод namedtuple _asdict.

Однако он возвращает OrderedDict, который pprint не будет отступать, поэтому я конвертирую его в dict:

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

С pprint и dict:

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

Ответ 2

PpttyPrinter в Python 3 гораздо более расширяем, чем раньше, на Python 2. Вы могли бы создать свой собственный принтер, как показано ниже, чтобы добавить методы для объекта, который вы хотите обработать, не слишком много перепутывая с помощью методов pprint "private" и атрибуты.

Здесь вы можете увидеть онлайн-пример: https://repl.it/HkDd/1

from io import StringIO
import pprint

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

и используйте его так:

from collections import namedtuple

Segment = namedtuple('Segment', 'p1 p2')
# Your own namedtuple-like class
class 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 demo
node = 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 = segments

pp = MyPrettyPrinter(indent=2, depth=2)
pp.pprint(node)

выходы

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=[...]))])