I have an abstract base class representing an interface. Subclasses of this class store as properties other subclasses of this class.
For example:
class AbstractBase(object):
pass
class Child(AbstractBase):
def __init__(self, cls1, cls2):
assert isinstance(cls1, AbstractBase)
assert isinstance(cls2, AbstractBase) # just to show they're instances
self.cls1 = cls1
self.cls2 = cls2
The depth and layout of the hierarchy cannot be known in advance, but will not be recursive.
What can I put as __repr__
on AbstractBase
that will allow me to see the proprties of each child class in a useful way?
My current approach is:
from pprint import pformat
class AbstractBase(object):
def __repr__(self):
return self.__class__.__name__ + '\n' \
+ pformat({k:v for k,v in self.__dict__.iteritems()
if not '__' in k})
For a base class (with no properties which are subclasses of AbstractBase
, this outputs something readable, eg:
MyClass
{'var1': 1,
'var2': 2}
However, for classes with AbstractBase
subclasses it breaks, as it's hard to tell where a parent class starts and another ends (given that further levels of nesting aren't given further indenting by the __repr__
above).
I'd be happy with something like the below, imagining cls1
and cls2
had a single int property var
:
Child
{'cls1': {
'var': 1,
},
'cls2': {
'var': 0,
}
}
Sadly, I don't know how to achieve this (or if it's even possible). Any thoughts?
I like what I got doing it this way:
class AbstractBase(object):
def __repr__(self, indent=2):
result = self.__class__.__name__ + '\n'
for k,v in self.__dict__.iteritems():
if k.startswith('__'):
continue
if isinstance(v, AbstractBase):
vStr = v.__repr__(indent + 2)
else:
vStr = str(v)
result += ' '*indent + k + ': ' + vStr
result += '\n'
return result
This is a slightly modified version of what John Zwinck proposed.
It considers how to format sequences, and changes the format slightly. It's not perfect at the moment, though - I think in particular, it will break for dictionaries, as the iterable component will only print the key.
def __repr__(self, indent=2):
result = self.__class__.__name__ + '\n'
items = self.__dict__.items()
for i,(k,v) in enumerate(items):
if '__' in k:
continue
if isinstance(v, AbstractBase):
vStr = '\n' + ' '*(indent + 2) + v.__repr__(indent + 4)
elif isinstance(v, collections.Iterable):
s = str(v)
bstart = s[0]
bend = s[-1]
newIndent = indent + 3
vStr = '\n' + ' '*(newIndent - 1) + bstart
for j,item in enumerate(v):
if isinstance(item, AbstractBase):
if j:
vStr += ' '*newIndent
vStr += item.__repr__(newIndent + 2)
else:
vStr += repr(item)
vStr += ',\n'
vStr += ' '*(newIndent - 1) + bend
else:
vStr = str(v)
result += ' '*indent + k + ': ' + vStr
if i != len(items) - 1:
result += '\n'
result = re.sub('\n+', '\n', result)
return result
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With