module exports a property instead of a class -- Evil?

gry at ll.mit.edu gry at ll.mit.edu
Fri Apr 29 14:02:59 EDT 2005


I often find myself wanting an instance attribute that can take on only
a few fixed symbolic values. (This is less functionality than an enum,
since there are no *numbers* associated with the values).  I do want
the thing to fiercely object to assignments or comparisons with
inappropriate values.  My implementation below gets me:

.import mode
.class C(object):
.   status = mode.Mode('started', 'done', 'on-hold')
.
.c=C()
.c.status = 'started'
.c.status = 'stated': #Exception raised
.if c.status == 'done': something
.if c.status == 'stated': #Exception raised
.if c.status.done: something  #simpler and clearer than string compare
.if c.status < 'done': something # Mode arg strings define ordering

I would appreciate comments on the overall scheme, as well as about the
somewhat sneaky (I think) exporting of a property-factory instead of a
class.  My intent is to provide a simple clear interface to the client
class ("C" above), but I don't want to do something *too* fragile or
confusing...
(I'd also welcome a better name than "Mode"...)

-------------------------- mode.py ----------------------
class _Mode:  #internal use only, not exported.
    def __init__(self, *vals):
        if [v for v in vals if not isinstance(v, str)]:
            raise ValueError, 'Mode values must be strings'
        else:
            self.values = list(vals)

    def set(self, val):
        if val not in self.values:
            raise ValueError, 'bad value for Mode: "%s"' % val
        else:
            self.state = val

    def __cmp__(self, other):
        if other in self.values:
            return cmp(self.values.index(self.state),
self.values.index(other))
        else:
            raise ValueError, 'bad value for Mode comparison'

    def __getattr__(self, name):
        if name in self.values:
            return self.state == name
        else:
            raise AttributeError, 'no such attribute: "%s"' % name


def Mode(*vals): # *function* returning a *property*, not a class.
    m = _Mode(*vals)
    def _insert_mode_get(self):
        return m
    def _insert_mode_set(self, val):
        m.set(val)
    return property(_insert_mode_get, _insert_mode_set)
-----------------------------------------------------------

Thanks,
    George




More information about the Python-list mailing list