It bugs me that the default __repr__() for a class is so uninformative:
>>> class Opaque(object): pass
...
>>> Opaque()
<__main__.Opaque object at 0x7f3ac50eba90>
… so I’ve been thinking about how to improve it. After a little consideration, I came up with this abstract base class which leverages the pickle protocol’s __getnewargs__() method:
from abc import abstractmethod
class Repro(object):
"""Abstract base class for objects with informative ``repr()`` behaviour."""
@abstractmethod
def __getnewargs__(self):
raise NotImplementedError
def __repr__(self):
signature = ", ".join(repr(arg) for arg in self.__getnewargs__())
return "%s(%s)" % (self.__class__.__name__, signature)
Here’s a trivial example of its usage:
class Transparent(Repro):
"""An example of a ``Repro`` subclass."""
def __init__(self, *args):
self.args = args
def __getnewargs__(self):
return self.args
… and the resulting repr() behaviour:
>>> Transparent("an absurd signature", [1, 2, 3], str)
Transparent('an absurd signature', [1, 2, 3], <type 'str'>)
>>>
Now, I can see one reason Python doesn’t do this by default straight away – requiring every class to define a __getnewargs__() method would be more burdensome than expecting (but not requiring) that it defines a __repr__() method.
What I’d like to know is: how dangerous and/or fragile is it? Off-hand, I can’t think of anything that could go terribly wrong except that if a Repro instance contained itself, you’d get infinite recursion … but that’s solveable, at the cost of making the code above uglier.
What else have I missed?
One problem with this whole idea is that there can be some kinds of objects who’s state is not fully dependent on the arguments given to its constructor. For a trivial case, consider a class with random state:
There’s no way for this class to correctly implement
__getnewargs__, and so your implantation of__repr__is also impossible. It may be that a class like the one above is not well designed. Butpicklecan handle it with no problems (I assume using the__reduce__method inherited fromobject, but my pickle-fu is not enough to say so with certainty).This is why it is nice that
__repr__can be coded to do whatever you want. If you want the internal state to be visible, you can make your class’s__repr__do that. If the object should be opaque, you can do that too. For the class above, I’d probably implement__repr__like this: