Docstrings for class attributes

George Sakkis george.sakkis at gmail.com
Tue Sep 23 13:50:52 EDT 2008


On Sep 23, 1:23 am, "Tom Harris" <celephi... at gmail.com> wrote:

> Greetings,
>
> I want to have a class as a container for a bunch of symbolic names
> for integers, eg:
>
> class Constants:
>     FOO = 1
>     BAR = 2
>
> Except that I would like to attach a docstring text to the constants,
> so that help(Constants.FOO) will print some arbitrary string. Sort of
> a very limited implementation of PEP 224. The only solution that I can
> see is to subclass int.__new__(), since once I have an int all it's
> attributes are immutable.

Here's one approach, using metaclasses and descriptors; it sort of
works, but it's less than ideal, both in usage and implementation.

George

#====== usage ============================================

class MyConstants:
    __metaclass__ = ConstantsMeta
    FOO = const(1, 'some docs about foo')
    BAR = const(2)

print MyConstants.FOO.__doc__
help(MyConstants.FOO)
print MyConstants.FOO - MyConstants.BAR
print MyConstants.FOO - 2
print 1 - MyConstants.BAR

#======= implementation ===================================

def ConstantsMeta(name, bases, namespace):
    for name,attr in namespace.iteritems():
        if isinstance(attr, const):
            namespace[name] = _ConstDescriptor(name, attr.value,
attr.doc)
    return type(name, bases, namespace)

class const(object):
    def __init__(self, value, doc=None):
        self.value = value
        self.doc = doc

class _ConstDescriptor(object):
    def __init__(self, name, value, doc):
        cls = type(name, (), dict(
            __doc__ = doc,
            __add__ = lambda self,other: value+other,
            __sub__ = lambda self,other: value-other,
            # ...
            __radd__ = lambda self,other: other+value,
            __rsub__ = lambda self,other: other-value,
            # XXX lots of boilerplate code for all special methods
follow...
            # XXX Is there a better way ?
        ))
        self._wrapper = cls()

    def __get__(self, obj, type):
        return self._wrapper



More information about the Python-list mailing list