PEP 813 - The Pretty Print Protocol

I would love to see this affect __repr__ by default as well.

This was suggested earlier in this thread as a change to the default repr() behind a __future__ import, but it seems like changing the default object.__repr__ implementation wouldn’t necessitate a __future__ import, since a custom __repr__ would overwrite it.

I’m imagining that the default __repr__ implementation would become effectively be something like:

def __repr__(self):
    cls = type(self)

    if not hasattr(self, "__pprint__"):
        # The current __repr__ behavior
        return f"<{cls.__module__}.{cls.__name__} object at {hex(id(self))}>"

    arguments = []
    for item in self.__pprint__():
        match item:
            case tuple((name, value, default)) if value == default:
                continue
            case tuple((name, value)) | tuple((name, value, _)) if name:
                arguments.append(f"{name}={value!r}")
            case tuple((_, value)):
                arguments.append(repr(value))
            case value:
                arguments.append(repr(value))
    return f"{cls.__name__}({', '.join(arguments)})"

This way instead of implementing both __pprint__ and __repr__ for each class:

class Bass:
    def __init__(self, strings: int, pickups: str, active: bool=False):
        self._strings = strings
        self._pickups = pickups
        self._active = active

    def __repr__(self):
        class_name = type(self).__name__
        if self._active is False:
            return f"{class_name}({self._strings}, pickups={self._pickups})"
        return f"{class_name}({self._strings}, pickups={self._pickups}, active={self._active})"

    def __pprint__(self):
        yield self._strings
        yield 'pickups', self._pickups
        yield 'active', self._active, False

I could just implement __pprint__ and get nice repr and str output for free:

class Bass:
    def __init__(self, strings: int, pickups: str, active: bool=False):
        self._strings = strings
        self._pickups = pickups
        self._active = active

    def __pprint__(self):
        yield self._strings
        yield 'pickups', self._pickups
        yield 'active', self._active, False

In that case, I do wonder whether __pprint__ should be renamed to something like __repr_args__.

From this comment from @barry it sounds like this might be out of scope for this PEP… but I wanted to note it as I have long wanted something to make generating repr output easier (just made a thread on this) and something to more make extending repr output in subclasses easier. This seems like it could accomplish both.

3 Likes