8

I have a nested dictionary structure with tuple keys. Here's what an entry looks like when I pretty-print the dictionary using pprint:

...
 ('A', 'B'): {'C': 0.14285714285714285,
              'D': 0.14285714285714285,
              'E': 0.14285714285714285,
              'F': 0.14285714285714285,
              'G': 0.14285714285714285,
              'H': 0.14285714285714285,
              'I': 0.14285714285714285},
...

It's pretty nifty, but I'd like to customize it further by cutting down some extra digits from the floats. I was thinking that it'd be possible to achieve by subclassing pprint.PrettyPrint but I don't know how that would be done.

Thanks.

Berk Özbalcı
  • 3,016
  • 3
  • 21
  • 27

1 Answers1

6

As you said, you can achieve this by subclassing PrettyPrinter and overwriting the format method. Note that the output is not only the formatted string, but also some flags.

Once you're at it, you could also generalize this and pass a dictionary with the desired formats for different types into the constructor:

class FormatPrinter(pprint.PrettyPrinter):

    def __init__(self, formats):
        super(FormatPrinter, self).__init__()
        self.formats = formats

    def format(self, obj, ctx, maxlvl, lvl):
        if type(obj) in self.formats:
            return self.formats[type(obj)] % obj, 1, 0
        return pprint.PrettyPrinter.format(self, obj, ctx, maxlvl, lvl)

Example:

>>> d = {('A', 'B'): {'C': 0.14285714285714285,
...                   'D': 0.14285714285714285,
...                   'E': 0.14285714285714285},
...       'C': 255}
...
>>> FormatPrinter({float: "%.2f", int: "%06X"}).pprint(d)
{'C': 0000FF,
 ('A', 'B'): {'C': 0.14,
              'D': 0.14,
              'E': 0.14}}
tobias_k
  • 81,265
  • 12
  • 120
  • 179
  • 1
    what about `super(FormatPrinter, self)` instead of `pprint.PrettyPrinter`? – Azat Ibrakov Jun 04 '17 at 17:30
  • 2
    You probably want to take general formatting functions. So `FormatPrinter({float: '{0:.2f}'.format})`, and have it `return self.formats[type(obj)](obj)`. – Artyer Jun 04 '17 at 17:30
  • @Artyer Yes, that's a possibility, too. Might be more versatile than just passing the format strings, but also a bit more verbose. – tobias_k Jun 04 '17 at 17:40
  • @Artyer Yeah, that's what I did. Thanks for your additional input. :) – Berk Özbalcı Jun 04 '17 at 17:44
  • Thank you for your input. I use your code with the following changes: def __init__(self, **kwargs): kwargsNext = { key: kwargs[key] for key in kwargs if key != 'formats' } super().__init__(**kwargsNext) self.formats = kwargs['formats'] – Roman Dec 04 '20 at 04:55