G
gry
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)
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)