Behaviour of enumerated types (was: Re: Immutable instances, constant values)

Bengt Richter bokr at
Fri Nov 18 22:38:06 CET 2005

On Fri, 18 Nov 2005 23:43:10 +1100 (EST), Ben Finney <bignose+hates-spam at> wrote:

>Bengt Richter <bokr at> wrote:
>> Ben Finney <bignose+hates-spam at> wrote:
>> >I've recently packaged 'enum' in PyPI.
>> [...]
>> My notion of enum comes from (what I remember of) Pascal
>You might want to investigate the 'enum' package for my idea of how an
>enumerated type can work.
I guess I saw an earlier version, and got confused as to the goal, sorry.
I will look in PyPI.
>> which is basically an ordered set of names of integers forming a
>> type, and ord(one_of_the_names) gets you the index value.
>Getting a numeric index might be useful in a language such as Pascal,
>with no built-in dict or sequence types. In Python, where any
>immutable object can be a dict key, and any sequence can be iterated,
>it seems of no use.
Does your concept of enumeration not have a fixed order of a set of names?
If it does, what is more natural than using their index values as keys
to other ordered info? OTOH, the index values (and hence my enums) are[1] not
very good as unique dict keys, since they compare[2] promiscuously with each other
and other number types. Hm, maybe if hash were defined class-unique, e.g.,
    def __hash__(self): return hash((int(self), type(self).__name__)
Ok, did that, _seems_ to work (fixed __repr__ too):
[1] were & [2] compared ;-)

 >>> from makeenum import makeEnum
 >>> Few = makeEnum('Few','zero one two three')
 >>> Few()
 >>> d = dict((Few(n), Few.names.index(n)) for n in Few.names)
 >>> d
 {Few('zero'): 0, Few('three'): 3, Few('one'): 1, Few('two'): 2}
 >>> d[1]
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 KeyError: 1
 >>> d[Few(1)]

But still can work as integer:
 >>> 'ABC'[Few(1)]
 >>> 'ABC'[Few('one')]
 >>> 'ABC'[Few('two')]

>> But what we have is named integers, much as True and False are built
>> in names for integer subtypes with value 1 and 0.
>That's an implementation detail; surely code shouldn't be expecting
>any particular relationship between integers and boolean values?
Au contraire, much code depends on it, e.g.,

 >>> def verboselen(s): return '%r has %d element%s'%(s, len(s), ('s','')[len(s)==1])
 >>> verboselen(range(3))
 '[0, 1, 2] has 3 elements'
 >>> verboselen(range(0))
 '[] has 0 elements'
 >>> verboselen(range(1))
 '[0] has 1 element'

 >>> type(len(range(3))==1)
 <type 'bool'>
 >>> type(len(range(3))==1).mro()
 [<type 'bool'>, <type 'int'>, <type 'object'>]
 >>> int (len(range(3))==1)
 >>> int (len(range(1))==1)

>> So I'd say enums should also be int subtypes...
>Likewise, that seems best left as an implementation detail. Why expect
>any particular mapping to int values? Doing arithmetic or boolean
>logic on enumerated values seems against their purpose.
I guess I will have to look at your enum in PyPI to understand what
you mean by "their purpose" ;-)

To me the int correspondence is as expectable and natural as a,b,c=range(3)
(at least as a default) though I think different enumerations should be
different types. Note that the ordering of int values makes the instances
nicely sortable too, e.g.,

 >>> d.items()
 [(Few('zero'), 0), (Few('three'), 3), (Few('one'), 1), (Few('two'), 2)]
 >>> sorted(d.items())
 [(Few('zero'), 0), (Few('one'), 1), (Few('two'), 2), (Few('three'), 3)]

or more directly

 >>> d.keys()
 [Few('zero'), Few('three'), Few('one'), Few('two')]
 >>> sorted(d.keys())
 [Few('zero'), Few('one'), Few('two'), Few('three')]

Enumerations defined as monotonic but non-contiguous sequences of named int
values are conceivable too. They can be useful in defining bit masks with
distinguishable types, but that act like ints. Kind of a sparse enumeration.
Maybe I'll add that in.

But bottom line, I really thing the int base type is more than an implementation
detail. I think it's natural for an _ordered_ set of names ;-)

I'll go look at PyPI now ;-)

Bengt Richter

More information about the Python-list mailing list