When you don't provide a __repr__
or __str__
method on a custom class, you just get a classname and the Python address of the object (or, to be more specific, what id(self)
would return.
This is fine most of the time. And it is very helpful when you are debugging some code and you want to see if instances are/are not the same, visually. But to be honest I almost never care about that id value.
However it also means that running a program with debugging print functions never looks the same. Ditto if you are comparing log files. Unless you write a lot of __repr__
only to avoid this issue. Or if you pre-format the log files to zero out the hex values on the default object prints.
class ILookDifferentEveryRun:
"baseline behavior"
def __init__(self,a):
"I don't actually care about `a`, that's why I don't need a `repr`"
self.a = a
class ILookTheSameEveryRun(ILookDifferentEveryRun):
"""this is my workaround, a cut and paste of a default __repr__"""
def __repr__(self) : return type(self).__name__
class ILookAlmostLikeBuiltinRepr(ILookDifferentEveryRun):
"can I do this with a global switch?"
def __repr__(self) :
"""this is more or less what I want"""
res = f"<{type(self).__module__}.{type(self).__name__} object> at <dontcare>"
return res
inst1 = ILookDifferentEveryRun(a=1)
inst2 = ILookTheSameEveryRun(a=1)
inst3 = ILookAlmostLikeBuiltinRepr(a=1)
print(inst1)
print(inst2)
print(inst3)
run twice:
<__main__.ILookDifferentEveryRun object at 0x100573260>
ILookTheSameEveryRun
<__main__.ILookAlmostLikeBuiltinRepr object> at <dontcare>
<__main__.ILookDifferentEveryRun object at 0x104ca7320>
ILookTheSameEveryRun
<__main__.ILookAlmostLikeBuiltinRepr object> at <dontcare>
I took a look at the startup flags for the python interpreter, but nothing seems to allow for this. Any workarounds? I know I could also put the repr on a Mixin and reuse that everywhere, but that's ugly too.
If I can't, that's fine and that's what I am expecting to hear. Just wondering if someone else had the same problem and found a way.
p.s. this is less about dedicated printing of instances and more about things like print(mylist)
where mylist=[item1,item2,item3]
, generally any complex data structures with nested items in them.
As a workaround you can add your desired __repr__
to every user class that does not have a custom __repr__
defined anywhere in the MRO.
This can be done automaticallly by replacing builtins.__build_class__
, which implements the class
statement, with a wrapper function that applies the patch to the class that the original __build_class__
returns:
import builtins
def __repr__(self):
cls = type(self)
return f'<{cls.__module__}.{cls.__qualname__} object>'
def build_class(*args, orig_build_class=__build_class__, **kwargs):
cls = orig_build_class(*args, **kwargs)
if cls.__repr__ is object.__repr__:
cls.__repr__ = __repr__
return cls
builtins.__build_class__ = build_class
so that:
class A:
pass
print(A())
outputs:
<__main__.A object>