Skip to content

Pretty-printing makes things uglier in some cases #10609

Description

@BrenBarn

See for instance this StackOverflow question. There are two problems: subclassing a type that is normally pretty-printed in some cases loses the pretty-printing, and adding a custom __repr__ to a class that does not define its own pretty-printing has no effect.

Here is a simple illustration of the behavior:

In [1]: from collections import OrderedDict
   ...:
   ...: class Ugly(OrderedDict):
   ...:     pass
   ...:
   ...: class Pretty(OrderedDict):
   ...:     def __repr__(self):
   ...:         return "I feel pretty!"
   ...:

In [2]: OrderedDict(a=1, b=2, c=3, d=4, e=5, f=6, g=8)
Out[2]:
OrderedDict([('a', 1),
             ('c', 3),
             ('b', 2),
             ('e', 5),
             ('d', 4),
             ('g', 8),
             ('f', 6)])

In [3]: Ugly(a=1, b=2, c=3, d=4, e=5, f=6, g=8)
Out[3]: Ugly([('a', 1), ('c', 3), ('b', 2), ('e', 5), ('d', 4), ('g', 8), ('f', 6)])

In [4]: Pretty(a=1, b=2, c=3, d=4, e=5, f=6, g=8)
Out[4]: Pretty([('a', 1), ('c', 3), ('b', 2), ('e', 5), ('d', 4), ('g', 8), ('f', 6)])

The output of OrderedDict is prettified. Ugly inherits from OrderedDict with no modifications, but is not prettified. Pretty inherits from OrderedDict and tries to make its own prettier __repr__, but it has no effect. To add insult to injury, the output for Pretty is not only not the output Pretty defined for itself, but is even uglier than the output for the plain OrderedDict.

The thing is that using a special pretty-printer is only better when you know what __repr__ it's replacing. Otherwise you may be replacing a pretty __repr__ with an uglier one. The pretty printer is better than the default __repr__ for something like OrderedDict, but if someone writes their own __repr__, they're saying they want that to be used instead of the default, and it's irritating to have IPython override that. It is also especially annoying that the pretty-printing behavior prettifies the output of, say, OrderedDict, but does not prettify the output of a user-defined subclass of OrderedDict, and yet still blocks the user from doing so by overriding __repr__.

I'm not 100% sure, but I'm tempted to say that the right solution is to only use the pretty printer if the class defines a _repr_pretty, or if the __repr__ is defined by a hand-curated list of "known ugly printers" (e.g., OrderedDict). If a user-defined class defines its own __repr__ (and doesn't define _repr_pretty), then that should always be used.

The trick is that, to do this right, we would need to not just check the object's class, but actually determine which class is defining the __repr__. That is, if a subclass of OrderedDict doesn't override __repr__, the pretty printer should be used; if the subclass does override __repr__, the custom __repr__ should be used instead of the pretty-printer. So the order of priority is:

  1. _repr_pretty
  2. __repr__ defined in a class that we don't know is ugly.
  3. Default pretty print
  4. __repr__ defined in a class that we know is ugly

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions