A generic attribute container, with pretty printing and recursion protection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | def recursion_lock(retval, lock_name = "____recursion_lock"):
def decorator(func):
def wrapper(self, *args, **kw):
if getattr(self, lock_name, False):
return retval
setattr(self, lock_name, True)
try:
return func(self, *args, **kw)
finally:
setattr(self, lock_name, False)
return wrapper
return decorator
class Container(object):
def __init__(self, **kw):
self.__dict__.update(kw)
@recursion_lock("<...>")
def __repr__(self):
attrs = sorted("%s = %r" % (k, v) for k, v in self.__dict__.iteritems() if not k.startswith("_"))
return "%s(%s)" % (self.__class__.__name__, ", ".join(attrs))
@recursion_lock("<...>")
def __str__(self, nesting = 1):
attrs = []
indentation = " " * nesting
for k, v in self.__dict__.iteritems():
if not k.startswith("_"):
text = [indentation, k, " = "]
if isinstance(v, Container):
text.append(v.__str__(nesting + 1))
else:
text.append(repr(v))
attrs.append("".join(text))
attrs.sort()
attrs.insert(0, self.__class__.__name__ + ":")
return "\n".join(attrs)
---------
example:
---------
>>> c = Container(a=1, b="baaa")
>>> c # calls repr()
Container(a = 1, b = 'baaa')
>>> print c # calls str()
Container:
a = 1
b = 'baaa'
>>> c.c = 1.23
>>> print c
Container:
a = 1
b = 'baaa'
c = 1.23
>>> c.d = Container(e = 6, f = "g")
>>> c
Container(a = 1, b = 'baaa', c = 1.23, d = Container(e = 6, f = 'g'))
>>> print c
Container:
a = 1
b = 'baaa'
c = 1.23
d = Container:
e = 6
f = 'g'
>>> c.h = c # recursive referencing
>>> c
Container(a = 1, b = 'baaa', c = 1.23, d = Container(e = 6, f = 'g'), h = <...>)
>>> print c
Container:
a = 1
b = 'baaa'
c = 1.23
d = Container:
e = 6
f = 'g'
h = <...>
>>>
|
similar to the Bunch class that's been on the cookbook since 2001, but better. support pretty representations. very handy as a container for parsed data, etc., where attributes are added dynamically, and you want pretty printing for debugging/demonstrating. it is used extensively in my pyConstruct parsing library.
see also the ExceptionContainer recipe