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