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

2005-04-29 Thread Bengt Richter
On 29 Apr 2005 11:02:59 -0700, gry@ll.mit.edu wrote:

>I often find myself wanting an instance attribute that can take on only

without checking deeply, are you not sharing state among all instance?
See following for an alternative way, allowing initialization by a
first assignment of a name sequence, followed by normal operation on
a per instance basis.

>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)
>---
>
Not tested beyond what you see ;-)

< state.py 
>--
# set up to validate state name strings
namerefcode = compile('a','','eval').co_code
non_name_chars = []
for c in (chr(i) for i in xrange(256)):
try:
if compile(c, '', 'eval').co_code != namerefcode:
non_name_chars.append(c)
except (SyntaxError, TypeError):
non_name_chars.append(c)
non_name_chars = ''.join(non_name_chars)
idem = ''.join([chr(i) for i in xrange(256)])

class Status(object):
def __get__(self, inst, cls=None):
if inst is None: return self
if not '_state' in inst.__dict__:
raise ValueError, 'Uninitialized instance state names'
return inst._state
def __set__(self, inst, value):
if not hasattr(inst, '_state'): inst._state = self.State(*value)
else: inst._state._setv(value)

class State(object):
def __init__(self, *names):
for s in names:
   if s[:1].isdigit() or s!= s.translate(idem, non_name_chars):
raise ValueError, '%r is not a valid name'%s
self._names = list(names)
self._value = names[0]
def _name_ck(self, name):
if name not in self._names:
raise AttributeError(
'Legal names are: %s -- not %r' % (', '.join(map(repr, 
self._names)), name)) 
def __getattr__(self, attr):
if attr.startswith('_'):
return object.__getattribute__(self, attr)
self._name_ck(attr)
return self._value == attr
def _setv(self, value):
self._name_ck(value)
self._value = value
def __cmp__(self, other):
self._name_ck(other)
return cmp(self._names.index(self._value), self._names.index(other))
def __str__(self):
return self._value

def test():
class C(object):
status = Status()
instances = [C(), C(), C()]
nameslist = map(str.split, ['started done on_hold', 'one two three', 'UNK 
running stopped'])
for i, (inst, names) in enumerate(zip(instances, nameslist)):
inst.status = names
inst.status = names[i]
print 'Instance %s names: %r' %(i, inst.status._names)
for i, inst in en

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

2005-04-29 Thread gry
Hmm, I had no idea that "property" was a class.  It's listed in the
library
reference manual under builtin-functions.  That will certainly make
things neater.  Thanks!

-- George

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


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

2005-04-29 Thread Lonnie Princehouse
The property factory is nice, but have you considered subclassing
property?

class Mode(property):
  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)
property.__init__(self, self.get, self.set)
  def get(self, instance):
 ... 
  def set(self, instance, value):
 ...

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


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

2005-04-29 Thread 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)
---

Thanks,
George

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