I'm made an AutoRepr
class and class decorator
...
class AutoRepr:
def __repr__(self):
def _fix(thing):
if isinstance(thing, str):
return f'"{thing}"'
if isinstance(thing, Iterable):
s = str(thing)
if len(s) > 30:
return type(thing)
else:
return s
return thing
props = []
try:
for attr in self.__slots__:
if attr.startswith('_'):
continue
try:
attr_val = getattr(self, attr)
if attr_val:
props.append(f'{attr}={_fix(attr_val)}')
except AttributeError:
pass
except AttributeError:
props = [f'{k}={_fix(v)}'
for k, v in self.__dict__.items()
if not k.startswith('_')]
return f'{type(self).__name__}({", ".join(props)})'
def auto_repr(override_all=False):
def decorator(cls):
repr_defined_in = cls.__repr__.__qualname__.split('.')[0]
if not override_all and repr_defined_in == cls.__name__:
# repr overriden in class. Don't mess with it
return cls
cls.__repr__ = AutoRepr.__repr__
return cls
return decorator
# Example 1
@auto_repr()
class MyClass:
def __init__(self):
self.strength = None
self.weakness = 'cake'
# Example 2
class Another(AutoRepr):
__slots__ = ('num', 'my_list')
def __init__(self):
self.num = 12
self.my_list = [1, 2, 3]
f = MyClass()
print(f)
b = Another()
print(b)
# MyClass(strength=None, weakness="cake")
# Another(num=12, my_list=[1, 2, 3])
In the decorator, I need to check if the wrapped class __repr__
was overridden in the class or belongs to a parent class. If the __repr__
has been overriden by the class then I don't want auto_repr to do anything, however, if not then obviously want auto-repr to do it's thing. I managed to hack together a solution by comparing the string name of the repr methods bound class via __qualname__
, but it feels cheap and clunky. Ideally I'd like to check identity properly if cls is repr_defined_in_cls
.
All the SO questions I've seen only address getting the string name of the class, but not the class for comparison. Is there a better way to get the (originating) class which defined the method?