Docstrings for class attributes
Gerard flanagan
grflanagan at gmail.com
Tue Sep 23 15:55:30 EDT 2008
George Sakkis wrote:
> 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
> --
> http://mail.python.org/mailman/listinfo/python-list
>
I think you get an equivalent result if you forget the descriptor
and adapt the metaclass:
def ConstantsMeta(name, bases, namespace):
for name,attr in namespace.iteritems():
if isinstance(attr, const):
cls = type(name, (type(attr.value),), {'__doc__': attr.doc})
namespace[name] = cls(attr.value)
return type(name, bases, namespace)
class const(object):
def __init__(self, value, doc=None):
self.value = value
self.doc = doc
#====== 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
#==========================================================
Alternatively, forget the metaclass and have:
def const(name, val, doc=None):
return type(name, (type(val),), {'__doc__': doc})(val)
#====== usage ============================================
class MyConstants:
FOO = const('FOO', 1, 'some docs about foo')
BAR = const('BAR', 2)
MOO = const('MOO', 8.0, 'all about MOO')
#==========================================================
G.
More information about the Python-list
mailing list