Welcome, guest | Sign In | My Account | Store | Cart

A generic attribute container, with pretty printing and recursion protection

Python, 77 lines
 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

Created by tomer filiba on Sat, 13 May 2006 (PSF)
Python recipes (4591)
tomer filiba's recipes (12)

Required Modules

  • (none specified)

Other Information and Tasks