pythonrepr

Possibility to implement multiple repr strategies?


In Python, is there a way to implement multiple repr strategies on custom classes, to provide different representation styles, and that recursively on arbitrary data structures, so nested objects would be shown using the parent call's strategy, if available? Like this...

class SomeClass:
    def __init__(self, objects):
        self._objects = objects
    def __repr__(self):
        return f"Recursive default repr: {self._objects}"
    def __alternate_repr__(self):
        return f"Recursive alternate repr: {self._objects}"

a = SomeClass(["list", "of", "values"])
b = SomeClass(dict(nested_class=a))
c = SomeClass([b, 1, "..."])

repr(c)  # c,b,a shown using __repr__()
alternate_repr(c)  # c,b,a shown using __alternate_repr__()

Solution

  • You'd probably want repr() to do the right thing (e.g. when called by other library code), and that code wouldn't know about a __special_repr__ or whatever, so you'll need some more roundabout plumbing here.

    Using contextvars makes sure this is async/threading safe.

    import contextlib
    import contextvars
    
    ## Repr mode plumbing.
    
    _repr_mode = contextvars.ContextVar("repr_mode", default="normal")
    
    
    def get_repr_mode():
        return _repr_mode.get()
    
    
    @contextlib.contextmanager
    def with_repr_mode(mode):
        try:
            token = _repr_mode.set(mode)
            yield
        finally:
            _repr_mode.reset(token)
    
    
    ## Client classes using the repr mode.
    
    
    class SomeClass(str):
        def __repr__(self):
            if get_repr_mode() == "special":
                return f"SPECIAL ALL CAPS REPR! {self.upper()}"
            return super().__repr__()
    
    
    class SomeContainer(list):
        def __repr__(self):
            if get_repr_mode() == "special":
                return f"SPECIAL REPR!: {super().__repr__()}"
            return super().__repr__()
    
    
    ## Demo code.
    
    lst = SomeContainer([SomeClass("hello"), SomeClass("world")])
    
    print(repr(lst))
    
    with with_repr_mode("special"):
        print(repr(lst))
    

    This prints out

    ['hello', 'world']
    SPECIAL REPR!: [SPECIAL ALL CAPS REPR! HELLO, SPECIAL ALL CAPS REPR! WORLD]