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