best way to implement custom pretty-printers best way to implement custom pretty-printers xml xml

best way to implement custom pretty-printers


My solution was to replace pprint.PrettyPrinter with a simple wrapper that formats any floats it finds before calling the original printer.

from __future__ import divisionimport pprintif not hasattr(pprint,'old_printer'):    pprint.old_printer=pprint.PrettyPrinterclass MyPrettyPrinter(pprint.old_printer):    def _format(self,obj,*args,**kwargs):        if isinstance(obj,float):            obj=round(obj,4)        return pprint.old_printer._format(self,obj,*args,**kwargs)pprint.PrettyPrinter=MyPrettyPrinterdef pp(obj):    pprint.pprint(obj)if __name__=='__main__':    x=[1,2,4,6,457,3,8,3,4]    x=[_/17 for _ in x]    pp(x)


This question may be a duplicate of:


Using pprint.PrettyPrinter

I looked through the source of pprint. It seems to suggest that, in order to enhance pprint(), you’d need to:

  • subclass PrettyPrinter
  • override _format()
  • test for issubclass(),
  • and (if it's not your class), pass back to _format()

Alternative

I think a better approach would be just to have your own pprint(), which defers to pprint.pformat when it doesn't know what's up.

For example:

'''Extending pprint'''from pprint import pformatclass CrazyClass: passdef prettyformat(obj):    if isinstance(obj, CrazyClass):        return "^CrazyFoSho^"    else:        return pformat(obj)def prettyp(obj):    print(prettyformat(obj))# testprettyp([1]*100)prettyp(CrazyClass())

The big upside here is that you don't depend on pprint internals. It’s explicit and concise.

The downside is that you’ll have to take care of indentation manually.


If you would like to modify the default pretty printer without subclassing, you can use the internal _dispatch table on the pprint.PrettyPrinter class. You can see how examples of how dispatching is added for internal types like dictionaries and lists in the source.

Here is how I added a custom pretty printer for MatchPy's Operation type:

import pprintimport matchpydef _pprint_operation(self, object, stream, indent, allowance, context, level):    """    Modified from pprint dict https://github.com/python/cpython/blob/3.7/Lib/pprint.py#L194    """    operands = object.operands    if not operands:        stream.write(repr(object))        return    cls = object.__class__    stream.write(cls.__name__ + "(")    self._format_items(        operands, stream, indent + len(cls.__name__), allowance + 1, context, level    )    stream.write(")")pprint.PrettyPrinter._dispatch[matchpy.Operation.__repr__] = _pprint_operation

Now if I use pprint.pprint on any object that has the same __repr__ as matchpy.Operation, it will use this method to pretty print it. This works on subclasses as well, as long as they don't override the __repr__, which makes some sense! If you have the same __repr__ you have the same pretty printing behavior.

Here is an example of the pretty printing some MatchPy operations now:

ReshapeVector(Vector(Scalar('1')),              Vector(Index(Vector(Scalar('0')),                           If(Scalar('True'),                              Scalar("ReshapeVector(Vector(Scalar('2'), Scalar('2')), Iota(Scalar('10')))"),                              Scalar("ReshapeVector(Vector(Scalar('2'), Scalar('2')), Ravel(Iota(Scalar('10'))))")))))