Enums and Python

Donn Cave donn at u.washington.edu
Wed Jun 21 12:41:35 EDT 2000


Quoth claird at starbase.neosoft.com (Cameron Laird):
[ ... re sequence and symbolic indices vs. dict and text keys (I think?) ...]

| I'll say that more forcefully than Aahz does here:  while
| enums are often a marker of good taste in C coding, Python
| generally achieves the same results with a considerably
| cleaner reformulation in terms of dicts.  If you feel a
| need for enums while writing Python, you're probably missing
| out on a better (and not-so-reminiscent-of-C) coding.
|
| I've become rather dogmatic on this point.  I need the
| practice of working to falsify it.  If you have a specific
| algorithm you can share that you see as ripe for a Python
| enum, please tell us here; maybe we can suggest an
| alternative.

When I feel these pangs the object at hand is invariably a tuple
returned from a C module.  posix.stat, time.gmtime, et al.  What
I want, of course, isn't really enums but struct members.  So
I'm not sure if this is on topic - we got here because structs
turn into tuples, tuples take indices and no one can remember them.

I think the tuple is what we want, it's not like the authors
of these functions made a mistake and should have returned dicts
or objects with struct member attributes - I mean, that would
be wonderful but not worth the additional complexity in the C
module layer, especially considering that these constructs are
not only output but also input.  Suggest an alternative if you
want, but for me it would be a hard sell.

At a higher level, a wrapper is an option.  I append some code
I have used a little for this, for a struct with member attributes
that doesn't entirely lose its tuple.  If I remember right it's
even recursive, tuple inside a tuple will also have attributes
if its tuple-type is supported.  For lots of little structs on
BeOS.  It isn't really much of a solution though.  The tuple has
to be explicitly converted to this instance type, and generally
it's just a little more trouble than I'm usually willing to go to
just to get around the need to remember that tm_day is [2].

So, for stat we have ST_ATIME etc.  Even that is often more than
we can be bothered with (I bet st[6] far outnumbers st[ST_SIZE]),
but it's good that it's there.

	Donn Cave, donn at u.washington.edu
----------------------------------------
from structuple import Structuple

#  For demonstration, the stat struct.  The actual struct would be
#  supported by generated C code, and the code generator also makes
#  this subclass.
#
class stat(Structuple):
	_members = ('st_mode', 'st_ino', 'st_dev', 'st_nlink', 'st_uid', 'st_gid', 'st_size', 'st_atime', 'st_mtime', 'st_ctime')
	def typegen(self):
		#  Return class
		return (None, None, None, None, None, None, None, None, None, None)

---------------------------------------- structuple.py
#
#  Wrap tuple data types.
#
#  The types are structs that for economy are rendered in Python as
#  tuples, rather than internal C types.  The code generating module
#  that handles the C logic for this (sgrules) also generates Python
#  code for this wrapper system, so any time that's changed, the
#  wrapper structs module needs to be updated too.
#
#  This module contains the base class for the wrapper structs, and
#  is not generated.  Each derived class supplies a matched pair of
#  class-scope tuples, one naming the members and the other their types.
#  The type name (if any) is looked up and used to generate the data
#  item, on initialization and on assignment.  I think this is probably
#  infrequent, if not it should be optimized.
#

#  If there's a type, look it up and use it to generate the result.
#  This lookup is because I put the types in the class namespace -
#  a reference there to another class can fail if that class is defined
#  below the present class.
#
def tostruct(x, m, t):
	if t:
		return t(x)
	else:
		return x

def fromstruct(x, m, t):
	if t is None:
		return x
	else:
		return x.tuple

class Structuple:
	def __init__(self, t):
		if len(t) != len(self._members):
			raise TypeError, '%d-tuple' % len(t)
		self._types = self.typegen()
		self._dt = map(tostruct, t, self._members, self._types)

	def __getitem__(self, i):
		d = self._dt[i]

		#  Assuming you want tuple result rather than instance,
		#  if you ask via index.
		#
		if type(d) == type(self):
			d = d.tuple
		return d

	def __getattr__(self, a):
		if a == 'tuple':
			return tuple(map(fromstruct,
				self._dt, self._members, self._types))
		for i in range(len(self._dt)):
			if self._members[i] == a:
				return self._dt[i]
		raise AttributeError, a

	def __setattr__(self, a, v):
		if a in ('_dt', '_types'):
			self.__dict__[a] = v
			return
		for i in range(len(self._dt)):
			if self._members[i] == a:
				if type(v) == type(()):
					self._dt[i] = self._types[i](v)
				else:
					self._dt[i] = v
				return
		raise AttributeError, a
	def __str__(self):
		return str(self.tuple)
	def __repr__(self):
		return '<%s: %s>' % (self.__class__.__name__, self.tuple)



More information about the Python-list mailing list