George Sakkis wrote:
On Sep 23, 1:23 am, "Tom Harris" <[EMAIL PROTECTED]> 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.

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to