469,306 Members | 1,850 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,306 developers. It's quick & easy.

PEP 354: Enumerations in Python

Howdy all,

PEP 354: Enumerations in Python has been accepted as a draft PEP. The
current version can be viewed online:

<URL:http://www.python.org/peps/pep-0354.html>

Here is the reStructuredText source as it is today. Please discuss it
here so I can see what issues people may have.
PEP: 354
Title: Enumerations in Python
Version: $Revision: 42186 $
Last-Modified: $Date: 2006-01-26 11:55:20 +1100 (Thu, 26 Jan 2006) $
Author: Ben Finney <be********@benfinney.id.au>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 20-Dec-2005
Python-Version: 2.6
Post-History: 20-Dec-2005
Abstract
========

This PEP specifies an enumeration data type for Python.

An enumeration is an exclusive set of symbolic names bound to
arbitrary unique values. Values within an enumeration can be iterated
and compared, but the values have no inherent relationship to values
outside the enumeration.
Motivation
==========

The properties of an enumeration are useful for defining an immutable,
related set of constant values that have a defined sequence but no
inherent semantic meaning. Classic examples are days of the week
(Sunday through Saturday) and school assessment grades ('A' through
'D', and 'F'). Other examples include error status values and states
within a defined process.

It is possible to simply define a sequence of values of some other
basic type, such as ``int`` or ``str``, to represent discrete
arbitrary values. However, an enumeration ensures that such values
are distinct from any others, and that operations without meaning
("Wednesday times two") are not defined for these values.
Specification
=============

An enumerated type is created from a sequence of arguments to the
type's constructor::
Weekdays = enum('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat')
Grades = enum('A', 'B', 'C', 'D', 'F')
Enumerations with no values are meaningless. The exception
``EnumEmptyError`` is raised if the constructor is called with no
value arguments.

The values are bound to attributes of the new enumeration object::
today = Weekdays.mon
The values can be compared::
if today == Weekdays.fri: ... print "Get ready for the weekend"

Values within an enumeration cannot be meaningfully compared except
with values from the same enumeration. The comparison operation
functions return ``NotImplemented`` [#CMP-NOTIMPLEMENTED]_ when a
value from an enumeration is compared against any value not from the
same enumeration or of a different type::
gym_night = Weekdays.wed
gym_night.__cmp__(Weekdays.mon) 1 gym_night.__cmp__(Weekdays.wed) 0 gym_night.__cmp__(Weekdays.fri) -1 gym_night.__cmp__(23) NotImplemented gym_night.__cmp__("wed") NotImplemented gym_night.__cmp__(Grades.B) NotImplemented

This allows the operation to succeed, evaluating to a boolean value::
gym_night = Weekdays.wed
gym_night < Weekdays.mon False gym_night < Weekdays.wed False gym_night < Weekdays.fri True gym_night < 23 False gym_night > 23 True gym_night > "wed" True gym_night > Grades.B True

Coercing a value from an enumeration to a ``str`` results in the
string that was specified for that value when constructing the
enumeration::
gym_night = Weekdays.wed
str(gym_night) 'wed'

The sequence index of each value from an enumeration is exported as an
integer via that value's ``index`` attribute::
gym_night = Weekdays.wed
gym_night.index 3

An enumeration can be iterated, returning its values in the sequence
they were specified when the enumeration was created::
print [str(day) for day in Weekdays] ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']

Values from an enumeration are hashable, and can be used as dict
keys::
plans = {}
plans[Weekdays.sat] = "Feed the horse"
The normal usage of enumerations is to provide a set of possible
values for a data type, which can then be used to map to other
information about the values::
for report_grade in Grades:

... report_students[report_grade] = \
... [s for s in students if students.grade == report_grade]
Rationale -- Other designs considered
=====================================

All in one class
----------------

Some implementations have the enumeration and its values all as
attributes of a single object or class.

This PEP specifies a design where the enumeration is a container, and
the values are simple comparables. It was felt that attempting to
place all the properties of enumeration within a single class
complicates the design without apparent benefit.
Metaclass for creating enumeration classes
------------------------------------------

The enumerations specified in this PEP are instances of an ``enum``
type. Some alternative designs implement each enumeration as its own
class, and a metaclass to define common properties of all
enumerations.

One motivation for having a class (rather than an instance) for each
enumeration is to allow subclasses of enumerations, extending and
altering an existing enumeration. A class, though, implies that
instances of that class will be created; it is difficult to imagine
what it means to have separate instances of a "days of the week"
class, where each instance contains all days. This usually leads to
having each class follow the Singleton pattern, further complicating
the design.

In contrast, this PEP specifies enumerations that are not expected to
be extended or modified. It is, of course, possible to create a new
enumeration from the string values of an existing one, or even
subclass the ``enum`` type if desired.
Values related to other types
-----------------------------

Some designs express a strong relationship to some other value, such
as a particular integer or string, for each enumerated value.

This results in using such values in contexts where the enumeration
has no meaning, and unnecessarily complicates the design. The
enumerated values specified in this PEP export the values used to
create them, and can be compared for equality with any other value,
but sequence comparison with values outside the enumeration is
explicitly not implemented.
Hiding attributes of enumerated values
--------------------------------------

A previous design had the enumerated values hiding as much as possible
about their implementation, to the point of not exporting the string
key and sequence index.

The design in this PEP acknowledges that programs will often find it
convenient to know the enumerated value's enumeration type, sequence
index, and string key specified for the value. These are exported by
the enumerated value as attributes.
Implementation
==============

This design is based partly on a recipe [#ENUM-RECIPE]_ from the
Python Cookbook.

The PyPI package ``enum`` [#ENUM-PACKAGE]_ provides a Python
implementation of the data types described in this PEP.
References and Footnotes
========================

... [#CMP-NOTIMPLEMENTED]
The ``NotImplemented`` return value from comparison operations
signals the Python interpreter to attempt alternative comparisons
or other fallbacks.
<http://docs.python.org/ref/types.html#l2h-29>

... [#ENUM-RECIPE]
"First Class Enums in Python", Zoran Isailovski,
Python Cookbook recipe 413486
<http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413486>

... [#ENUM-PACKAGE]
Python Package Index, package ``enum``
<http://cheeseshop.python.org/pypi/enum/>
Copyright
=========

This document has been placed in the public domain.


...
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
--
\ Contentsofsignaturemaysettleduringshipping. |
`\ |
_o__) |
Ben Finney
Feb 27 '06
77 3499
Paul Rubin <http://ph****@NOSPAM.invalid> writes:
Ben Finney <bi****************@benfinney.id.au> writes:
If an enumeration object were to be derived from, I would think it
just as likely to want to have *fewer* values in the derived
enumeration. Subclassing would not appear to offer a simple way to
do that.


pentium_instructions = enum('add', 'sub', 'mul', ) # etc

athlon64_instructions = enum('add64', 'sub64', # etc
base_enum=pentium_instructions)

# 386 has no floating point unit
i386_instructions = enum(base_enum=pentium_instructions,
remove=('addf', 'subf', 'mulf',)) # etc


These don't seem simple or elegant. I don't see a particular benefit
to doing it that way, rather than being explicit about manipulating
the member list::

pentium_instructions = enum('add', 'sub', 'mul')
athlon64_instructions = enum(
*[ str(i) for i in pentium_instructions] + ['add64', 'sub64'] )
i386_instructions = enum(
*[ str(i) for i in pentium_instructions
if i not in ['addf', 'subf', 'mulf'] ] )

I don't see a benefit to having the enum constructor grow extra
keyword arguments for operating on lists, when a list has its own
methods for doing so.

--
\ "A fine is a tax for doing wrong. A tax is a fine for doing |
`\ well." -- Anonymous |
_o__) |
Ben Finney
Mar 1 '06 #51
Paul Rubin <http://ph****@NOSPAM.invalid> writes:
say that
Weekdays = enum('mon', 'tue', ...)

What is the type of Weekdays.mon supposed to be?


The specification doesn't mention that; it should.

I'm calling them EnumValue, but that makes it difficult to talk
about. The term "value" is commonly used to refer to an instance of a
type, so "enumeration value" sounds like an instance of the type
"enumeration", which is confusing.

Perhaps, since "collection" seems the right metaphor for an
enumeration, each of the values in an enumeration should be
EnumMember. On the assumption these might be basic types, though, that
name doesn't read so easily in lowercase ('enummember').

Thoughts?

--
\ "What I resent is that the range of your vision should be the |
`\ limit of my action." -- Henry James |
_o__) |
Ben Finney
Mar 1 '06 #52
Paul Rubin <http://ph****@NOSPAM.invalid> writes:
Do you anticipate having parameters like socket.AF_INET that are
currently integers, become enumeration members in future releases?


That, and the 're' flags referred to earlier, seems to be a good
application of enumerations.

--
\ "Jealousy: The theory that some other fellow has just as little |
`\ taste." -- Henry L. Mencken |
_o__) |
Ben Finney
Mar 1 '06 #53
Roy Smith <ro*@panix.com> writes:
A few random questions:

a = enum ('foo', 'bar', 'baz')
b = enum ('foo', 'bar', 'baz')
Two separate enumerations are created, and bound to the names 'a' and
'b'. Each one has three unique member values, distinct from any
others.
what's the value of the following:

a == b
False

(the enumeration objects are not the same, and don't contain the same
values)
a is b
False

(the enumeration objects are not the same)
a.foo == b.foo
False

(the comparison function returns NotImplemented when comparing values
from different enumerations. The Python interpreter [thanks Alex
Martelli :-)] will evaluate the comparison as False)
a.foo is b.foo
False

(the members of each enumeration are created as separate values)
len (a)
3

(enumerations are iterable)
str (a)
Not defined in the current specification. Suggestions?
repr (a)
Not defined in the current specification. Suggestions?
hash (a)
-1210774164 # or some other hash value

(falls back on the 'object' hash function)
type (a)
<type 'enum'> # if included in the language
<class 'collections.enum'> # if in the stdlib
Can you make an enum from a sequence?
The current specification is for an enum constructor to accept its
member names as separate arguments, to allow for the expected common
use case::

foo = enum('bar', 'baz', 'bucket')
syllables = ['foo', 'bar', 'baz']
c = enum (syllables)
Can be done with::

c = enum(*syllables)
You imply that it works from "An enumerated type is created from a
sequence of arguments to the type's constructor", but I suspect
that's not what you intended.
That's what I intended; a sequence of arguments. Is there a better way
to refer to the positional arguments collectively?
BTW, I think this is a great proposal; enums are a badly needed part
of the language.
Thanks. I hope we can arrive at a consensus view of how enums should
work in Python.
There's been a number of threads recently where people called
regex methods with flags (i.e. re.I) when integers were expected, with
bizarre results. Making the flags into an enum would solve the problem
while retaining backwards compatibility.


Yes, this is a prime use case for enums. I tried to cover this in the
"Motivation"::

Other examples include error status values and states
within a defined process.

Can anyone think of a better way to express this, without necessarily
referring to any specific set of flags or states or codes or whatever?

--
\ "To be yourself in a world that is constantly trying to make |
`\ you something else is the greatest accomplishment." -- Ralph |
_o__) Waldo Emerson |
Ben Finney
Mar 1 '06 #54
Steven Bethard <st************@gmail.com> writes:
Ben Finney wrote:
This PEP specifies an enumeration data type for Python.
An enumeration is an exclusive set of symbolic names bound to
arbitrary unique values. Values within an enumeration can be iterated
and compared, but the values have no inherent relationship to values
outside the enumeration.


-1 on the proposal as-is. I don't have many use cases for
enumerations, and I don't think they merit appearing in the builtins.
If you put them in the collections module instead, I'd probably be +0.


This seems to be a common distinction.

Should I amend the PEP to propose "either in the builtins or in the
collections module"? Or should I propose two PEPs and let them
compete?
This allows the operation to succeed, evaluating to a boolean value::
>>> gym_night = Weekdays.wed
>>> gym_night < Weekdays.mon

False
>>> gym_night < Weekdays.wed

False
>>> gym_night < Weekdays.fri

True
>>> gym_night < 23

False
>>> gym_night > 23

True
>>> gym_night > "wed"

True
>>> gym_night > Grades.B

True


For the few cases of enumerations that I've needed, I've never
wanted them to be comparable with <, >, etc. If there were two
classes, say ``collections.Enum`` and ``collections.OrderedEnum``
where only the latter made the enumerated items comparable, you
might even get me as high as +0.5. (I only care about the
non-comparable one, but I understand that others may have a need for
the comparable one.)


Replies to your post indicate this is another popular distinction.

But the terminology is broken. The term "enumerated" seems to me to
imply that it does have an order. Can you suggest a term other than
"enumerated" for what you're describing with the unordered property?

--
\ "For every complex problem, there is a solution that is simple, |
`\ neat, and wrong." -- Henry L. Mencken |
_o__) |
Ben Finney
Mar 1 '06 #55
Toby Dickenson <td********@devmail.geminidataloggers.co.uk> writes:
On Monday 27 February 2006 02:49, Ben Finney wrote:
Coercing a value from an enumeration to a ``str`` results in the
string that was specified for that value when constructing the
enumeration::


That sentence seems to assume that all enumeration values will have
been specified as strings. Thats reasonable, but your description of
the creation of an enumeration doesnt specify that.


True; I'll need to fix the specification so that it does say that.
An enumerated type is created from a sequence of arguments to the
type's constructor::
>>> Weekdays = enum('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat')
>>> Grades = enum('A', 'B', 'C', 'D', 'F')


s/arguments/strings/


s/arguments/string arguments/ :-)

--
\ "Too many pieces of music finish too long after the end." -- |
`\ Igor Stravinskey |
_o__) |
Ben Finney
Mar 1 '06 #56
Ben Finney <bi************@benfinney.id.au> writes:
PEP: 354
Title: Enumerations in Python
Version: $Revision: 42186 $
Last-Modified: $Date: 2006-01-26 11:55:20 +1100 (Thu, 26 Jan 2006) $


Most people seem to be unopposed or in favour of some kind of
enumeration mechanism making it at least as far as the standard
library.

As I understand it, the current outstanding debates are::

* Builtin types versus stdlib module (maybe 'collections')

* Ordered sequences versus unordered iterables

* Immutable versus mutable

* Bad comparisons: raise exception versus return NotImplemented

* Terminology for each of these concepts

Any new issues before I make a revised draft?

--
\ "It is seldom that liberty of any kind is lost all at once." |
`\ -- David Hume |
_o__) |
Ben Finney
Mar 1 '06 #57
Ben Finney <bi****************@benfinney.id.au> writes:
These don't seem simple or elegant. I don't see a particular benefit
to doing it that way, rather than being explicit about manipulating
the member list::

pentium_instructions = enum('add', 'sub', 'mul')
athlon64_instructions = enum(
*[ str(i) for i in pentium_instructions] + ['add64', 'sub64'] )


I don't know about this. It makes athlon64_instructions a completely
separate enum from pentium_instructions. It could be that
athlon64_instructions.add should be the same as pentium_instructions.add .
Mar 1 '06 #58
Em Seg, 2006-02-27 √*s 17:10 -0800, Paul Rubin escreveu:
Ben Finney <bi****************@benfinney.id.au> writes:
If an enumeration object were to be derived from, I would think it
just as likely to want to have *fewer* values in the derived
enumeration. Subclassing would not appear to offer a simple way to do
that.


pentium_instructions = enum('add', 'sub', 'mul', ) # etc

athlon64_instructions = enum('add64', 'sub64', # etc
base_enum=pentium_instructions)

# 386 has no floating point unit
i386_instructions = enum(base_enum=pentium_instructions,
remove=('addf', 'subf', 'mulf',)) # etc


Or maybe just...

i386_instructions = enum('add', 'sub', 'mul', ...)
pentium_instructions = enum(i386_instructions, 'addf', 'subf',
'mulf', ...)
athlon64_instructions = enum(pentium_instructions, 'add64',
'sub64', ...)
myprocessor_instructions = enum('foo', 'bar', 'baz', ...)
all_instructions = enum(athlon64_instructions,
myprocessor_instructions)

....and it could infer from the type that it's another enum to be
included. Also...

(i386_instructions.add == pentium_instructions.add ==
athlon64_instructions.add == all_instructions.add) == True

....and so on.

--
"Quem excele em empregar a força militar subjulga os exércitos dos
outros povos sem travar batalha, toma cidades fortificadas dos outros
povos sem as atacar e destrói os estados dos outros povos sem lutas
prolongadas. Deve lutar sob o Céu com o propósito primordial da
'preservação'. Desse modo suas armas não se embotarão, e os ganhos
poderão ser preservados. Essa é a estratégia para planejar ofensivas."

-- Sun Tzu, em "A arte da guerra"

Mar 1 '06 #59
Ben Finney <bi****************@benfinney.id.au> wrote:
a = enum ('foo', 'bar', 'baz')
b = enum ('foo', 'bar', 'baz')


Two separate enumerations are created


OK, most of the rest follows from that.
str (a)


Not defined in the current specification. Suggestions?


Well, by analogy with
a = set ((1, 2, 3))
print '%s' % a
set([1, 2, 3])

I would think:

enum('foo', 'bar', 'baz')

would make sense.
repr (a)


Not defined in the current specification. Suggestions?


Hmm. Maybe what I suggested for str() would work for repr() too. I'm a
little worried, however, about things that aren't == but print the same.
It might make more sense for repr() to include the id (in the style of
'<__main__.x instance at 0x8208f6c>'). Same with the repr() of an enum
member.
hash (a)


-1210774164 # or some other hash value


I saw some debate about mutable or immutable. Doesn't making something
hashable kinda-sorta mean it has to be immutable?
You imply that it works from "An enumerated type is created from a
sequence of arguments to the type's constructor", but I suspect
that's not what you intended.


That's what I intended; a sequence of arguments. Is there a better way
to refer to the positional arguments collectively?


I'm not really a language lawyer, so I can't say. I was mostly trying to
explore the corners of the envelope.
There's been a number of threads recently where people called
regex methods with flags (i.e. re.I) when integers were expected, with
bizarre results. Making the flags into an enum would solve the problem
while retaining backwards compatibility.


Yes, this is a prime use case for enums. I tried to cover this in the
"Motivation"::

Other examples include error status values and states
within a defined process.

Can anyone think of a better way to express this, without necessarily
referring to any specific set of flags or states or codes or whatever?


Cite the regex thread :-)
Mar 1 '06 #60

"Ben Finney" <bi****************@benfinney.id.au> wrote in message
news:87************@rose.polar.local...
Should I amend the PEP to propose "either in the builtins or in the
collections module"?
Yes, if the idea is accepted, Guido and devs will debate and decide that
anyway ;-)
Or should I propose two PEPs and let them compete?
No..
But the terminology is broken. The term "enumerated" seems to me to
imply that it does have an order. Can you suggest a term other than
"enumerated" for what you're describing with the unordered property?


Re flags are not ordered. Their bug proneness when given to wrong
functions is a point for your proposal.

tjr

Mar 1 '06 #61
Ben Finney wrote:
Steven Bethard <st************@gmail.com> writes:
Ben Finney wrote:
This PEP specifies an enumeration data type for Python.
An enumeration is an exclusive set of symbolic names bound to
arbitrary unique values. Values within an enumeration can be iterated
and compared, but the values have no inherent relationship to values
outside the enumeration. -1 on the proposal as-is. I don't have many use cases for
enumerations, and I don't think they merit appearing in the builtins.
If you put them in the collections module instead, I'd probably be +0.


This seems to be a common distinction.

Should I amend the PEP to propose "either in the builtins or in the
collections module"? Or should I propose two PEPs and let them
compete?


I would probably just amend the PEP. I have a feeling that python-dev
is even less likely to accept it as a builtin than python-list is.
For the few cases of enumerations that I've needed, I've never
wanted them to be comparable with <, >, etc. If there were two
classes, say ``collections.Enum`` and ``collections.OrderedEnum``
where only the latter made the enumerated items comparable, you
might even get me as high as +0.5. (I only care about the
non-comparable one, but I understand that others may have a need for
the comparable one.)


Replies to your post indicate this is another popular distinction.

But the terminology is broken. The term "enumerated" seems to me to
imply that it does have an order.


I didn't get that implication. From WordNet 2.0:

"""
enumerate

v 1: specify individually; "She enumerated the many obstacles she had
encountered"; "The doctor recited the list of possible side effects of
the drug" [syn: recite, itemize, itemise] 2: determine the number or
amount of; "Can you count the books on your shelf?"; "Count your change"
[syn: count, number, numerate]
"""

I don't get an ordering out of either of the definitions above. But
certainly there are a few precedents (e.g. Java's Enumeration interface)...
Can you suggest a term other than
"enumerated" for what you're describing with the unordered property?


I don't have any good names if people think that enumeration implies
ordering. Off of thesaurus.reference.com:

* numbering
* inventory
* lexicon
* catalogue

Those were the best I saw, and they're pretty bad. I guess you could go
with ``symbols`` maybe...

STeVe
Mar 1 '06 #62
Steven D'Aprano wrote:
You can't shell an egg that isn't there.


Yesterday upon the stair
I shelled an egg that wasn't there.
I'd shell the thing again today
If only I could find a way.

--
Greg
Mar 1 '06 #63
Ben Finney wrote:
On the assumption these might be basic types, though, that
name doesn't read so easily in lowercase ('enummember').


Maybe 'enumval'?

I also thought of 'enumber' (from munging together
'enum' and 'member') but that looks too much like
'e-number' rather than 'enum-ber'.

--
Greg
Mar 1 '06 #64
Paul Rubin wrote:
Do you anticipate having parameters like socket.AF_INET that are
currently integers, become enumeration members in future releases?


Since these are derived from values defined
as integers in C, it's probably better to leave
them that way. There may be code that relies
on them being integers or having those integer
values.

--
Greg
Mar 1 '06 #65
Giovanni Bajo wrote:
What's the repr of an enumeration value? OTOH, it should be something like
"Weekdays.wed", so that eval(repr()) holds true. Also, it'd be very useful in
debug dumps, tracebacks and whatnot.


That would be nice, but I don't think that's possible
with what the PEP proposes, because in

Weekdays = enum('mon', 'tue', etc...)

there's no way for the enum object to know that it's
meant to be called 'Weekdays'.

A constructor argument could be added for this, but
then you end up having to write the name twice,
making the construct far less elegant.

Maybe *this* is a good argument for making the enum
object a class?

Or maybe it's an argument for allowing decorators
to operate on things other than functions, so you
could write something like

@enum
Weekdays = ('mon', 'tue', etc...)

--
Greg
Mar 1 '06 #66
Dan Sommers wrote:
In some parts of the world, calendar weeks begin on Monday
and end on Sunday, and in other parts of the world, work weeks begin on
Sunday and end on Thursday.


Things like days of the week really have a circular
ordering, so it doesn't inherently make sense to
ask whether one day of the week is less than or
greater than another.

Maybe there should be a circular_enum type, where
order comparisons even among the *same* type are
disallowed?

Another thought -- should enum values have pred()
and succ() methods, like in Pascal? If so, for
a circular_enum these should wrap around.

--
Greg
Mar 1 '06 #67
In article <46************@individual.net>,
greg <gr**@cosc.canterbury.ac.nz> wrote:
Paul Rubin wrote:
Do you anticipate having parameters like socket.AF_INET that are
currently integers, become enumeration members in future releases?


Since these are derived from values defined
as integers in C, it's probably better to leave
them that way. There may be code that relies
on them being integers or having those integer
values.


On a thin API like python's socket module, adding anything which isn't
there in the lower level is a mistake (and making AF_INET an enum member
would be adding something which isn't there).

I just finished adding IPv6 support to a product that didn't have it
before. We've got a "platform independent" socket interface which treats
the address family as opaque data. It turns out, I had to make ZERO
changes to this shim layer. Had the layer known more about address
families, I would have had a lot more work to do.

Consider, for example, Python running on a system with experimental
AF_INET8 support at some point in the future. As it stands now, the Python
library code doesn't need to know there's a new address family if all you
want to do is open raw AF_INET8 sockets.
Mar 1 '06 #68
>> Do you anticipate having parameters like socket.AF_INET
that are currently integers, become enumeration members
in future releases?


Since these are derived from values defined as integers
in C, it's probably better to leave them that way. There
may be code that relies on them being integers or having
those integer values.


I'd say that "because something is done in C, it's the best
way to do it in Python" is a bad line of reasoning :) If I
wanted C, I'd use C. ("some C API functions take pointers
to arbitrary blocks of memory...python should [natively]
implement pointers to arbitrary blocks of memory..." kinda
scares me to be frank...that's why there's the ability to
write clean wrappers in C or C++ to expose such things)

The backwards-compatibility-with-existing-code is a much
better reason :)

-tkc

Mar 1 '06 #69
Tim Chase <py*********@tim.thechases.com> wrote:
Do you anticipate having parameters like socket.AF_INET
that are currently integers, become enumeration members
in future releases?


Since these are derived from values defined as integers
in C, it's probably better to leave them that way. There
may be code that relies on them being integers or having
those integer values.


I'd say that "because something is done in C, it's the best
way to do it in Python" is a bad line of reasoning :) If I
wanted C, I'd use C.


The problem is that the C language binding in this case is simply
exposing the even lower level operating system interface. At that
level, the address family is indeed just an arbitrary integer.

The socket man page on (for example) Solaris-9 says things like, "The
currently understood formats are", and "If a protocol is specified by
the caller, then it will be packaged into a socket level option
request and sent to the underlying pro- tocol layers". You don't
really know for sure if you used a valid value until the low-level
protocol drivers look at the number you passed in. This doesn't sound
like an enum to me.

There are plenty of places where we pass around integers that would be
better served by enums. Address families and protocol numbers in the
socket interface just isn't one of them.

Mar 1 '06 #70
[Ben Finney]
It is possible to simply define a sequence of values of some other
basic type, such as ``int`` or ``str``, to represent discrete
arbitrary values. However, an enumeration ensures that such values
are distinct from any others, and that operations without meaning
("Wednesday times two") are not defined for these values.


It would be useful for the PEP to add a section that discussed the pros
and cons of this approach (preferably with examples).

For instance, having values distinct from one another is only useful in
the absence of namespace qualifiers (such as Weekdays.fri).

Also, it would be useful to contrast this approach with that used for
Booleans which were implemented as an int subclass. There, the
interoperability with other numbers turned out to be useful on
occasion:

Q = lambda predicate, iterable: sum(predicate(val) for val in
iterable)

Likewise, the PEP's approach precludes a broad class of use cases such
as:

Weekday.fri - Weekday.wed == 2

(where Weekday.fri > Weekday.wed implies that the difference has a
positive value).

If enumerations were implemented as an int subclass, they could serve
as a base class for booleans and enter the language in a unified way.
Likewise, they could be more readily applicable in use cases like
calendar.py which relies on math ops being defined for the days of the
week.

I would like to see the PEP develop these arguments more fully so that
the correct approach will be self evident based on the merits.
Raymond

Mar 1 '06 #71
Paul Rubin schrieb:
But if you have a good usage case for an empty enum, please feel free
to tell us.


Do you have a good usage case for the number
64757429634024117340651643980663421727433660381596 8998799147348150763731 ?


Yes, it could be the value of my property in any currency :) But your
argument is wrong. There's no logical or even aesthetical reason to
have empty enums. An empty set is an instance of the set type like 0
or your big number are instances of the integer type and are neccessary
to make some operations complete. But an empty enum is a *type* without
values, therefore a type that cannot be instantiated i.e. a useless
type.

I don't like Python enums at all. It is kind of "I want to have that
C++ thing, too". In Python enums can be emulated so there's no need
to have syntactical support for them.

Peter Maas, Aachen
Mar 1 '06 #72
On Wed, 01 Mar 2006 12:26:19 +1100
Ben Finney <bi****************@benfinney.id.au> wrote:
Steven Bethard <st************@gmail.com> writes:
-1 on the proposal as-is. I don't have many use cases
for enumerations, and I don't think they merit appearing
in the builtins. If you put them in the collections
module instead, I'd probably be +0.


This seems to be a common distinction.

Should I amend the PEP to propose "either in the builtins
or in the collections module"? Or should I propose two
PEPs and let them compete?


My recommendation is to drop the "builtins" suggestion
altogether. If it goes into the stdlib and becomes popular,
write a PEP suggesting it move to builtins *then*. That
would follow the example of "sets".

I for one think that builtins is already too large (though
I admit I'm unsure what should be removed). Enumerations
are used infrequently enough that they should be a module
(e.g. "decimal" numbers are probably more common).
For the few cases of enumerations that I've needed, I've
never wanted them to be comparable with <, >, etc. If
there were two classes, say ``collections.Enum`` and
``collections.OrderedEnum`` where only the latter made
the enumerated items comparable, you might even get me
as high as +0.5. (I only care about the non-comparable
one, but I understand that others may have a need for
the comparable one.)


Replies to your post indicate this is another popular
distinction.

But the terminology is broken. The term "enumerated" seems
to me to imply that it does have an order. Can you suggest
a term other than "enumerated" for what you're describing
with the unordered property?


Well, I personally don't find the term that broken, but as
I say, the term "Vocabulary" has been used. There is "Open
Vocabulary" and "Closed Vocabulary" to define the mutable
and immutable cases respectively. But they're long names.

Plus, you need a name for the individual values. So there
are a number of possibilities:

EnumValue / Enum
Symbol / SymbolSet
Word / Vocabulary
Symbol / Vocabulary (what I used for "open" case)
Symbol / Enum (what I used for "closed" case)
Word / WordSet
Label / LabelSet

I'm sure there are others.

Word has the disadvantage of also meaning "32-bit integer"
to a lot of CS people. Or perhaps a string. Not
immediately an indivisible symbol.

Symbol probably has a dozen overloaded meanings, though
I'm not sure what other people will think when they read it
(it actually seems right to me, obviously).

Label was what I first called these. But I realize that
label describes a probably use of a symbol, not the symbol
itself.

--
Terry Hancock (ha*****@AnansiSpaceworks.com)
Anansi Spaceworks http://www.AnansiSpaceworks.com

Mar 2 '06 #73
On Wed, 01 Mar 2006 12:37:26 +1100
Ben Finney <bi****************@benfinney.id.au> wrote:
Ben Finney <bi************@benfinney.id.au> writes:
PEP: 354
Title: Enumerations in Python
Version: $Revision: 42186 $
Last-Modified: $Date: 2006-01-26 11:55:20 +1100 (Thu,
26 Jan 2006) $
Most people seem to be unopposed or in favour of some kind
of enumeration mechanism making it at least as far as the
standard library.


.... but not to built-ins. That seems about right to me.
As I understand it, the current outstanding debates are::

* Builtin types versus stdlib module (maybe
'collections')

* Ordered sequences versus unordered iterables

* Immutable versus mutable
I suggest that both are called for, but would have different
names -- the Immutable is the actual "Enum", the mutable is
probably a "Vocabulary" or something else.
* Bad comparisons: raise exception versus return
NotImplemented
It should raise an error, because client code should use
enumerated values if enumerated values are spec'd in the
API.
* Terminology for each of these concepts


+ Tracing of individual "EnumValues" (or "symbols"?) to
their enum, I should be able to interrogate a value to
find what enum it comes from in addition to being able
to interrogate an enum to find out what values belong
to it.

Which is more computationally efficient will depend
on the application, and a single application might
do better to use each for different tasks, so I think
it should be reversible.

+ How about documentation of enumerated values? (Where
does the enum's __doc__ go?). One of the main values
of using enumerated values is as an aid to documentation,
but "WED" is still vague. Could be "Wednesday", could
be the "Western Education District" or short for
"Wedding". Enumerations are most frequently used in
module APIs, so they are important to document.

Obviously, the point is so that documentation tools like
epydoc can capture the enumeration documentation.
--
Terry Hancock (ha*****@AnansiSpaceworks.com)
Anansi Spaceworks http://www.AnansiSpaceworks.com

Mar 2 '06 #74
>> Should I amend the PEP to propose "either in the builtins
or in the collections module"? Or should I propose two
PEPs and let them compete?


I see the issue of whether it's a built-in or part of the standard library
as being a detail. My personal opinion is that they're important enough to
be built in, but having to write "import enum" (or whatever) won't kill me.
If making it a builtin becomes a point of contention, drop it and
concentrate on the more key issues of how enums will behave.
Mar 2 '06 #75
Paul Rubin <http://ph****@NOSPAM.invalid> writes:
I don't know about this. It makes athlon64_instructions a
completely separate enum from pentium_instructions. It could be
that athlon64_instructions.add should be the same as
pentium_instructions.add .


If you want the members of two distinct collections to have a
meaningful relationship, you don't want enumerations. The basic
promise of the specified enumeration interface is that every member of
an enumeration is a unique value.

--
\ "A society that will trade a little liberty for a little order |
`\ will lose both, and deserve neither." -- Thomas Jefferson, in |
_o__) a letter to Madison |
Ben Finney
Mar 2 '06 #76
Ben Finney <bi****************@benfinney.id.au> writes:
I don't know about this. It makes athlon64_instructions a
completely separate enum from pentium_instructions. It could be
that athlon64_instructions.add should be the same as
pentium_instructions.add .


If you want the members of two distinct collections to have a
meaningful relationship, you don't want enumerations. The basic
promise of the specified enumeration interface is that every member of
an enumeration is a unique value.


The premise is that they're not necessarily distinct (disjoint)
collections; one of them has been explicitly created as a superset of
the other.
Mar 2 '06 #77
On 26 Feb 2006 22:30:28 -0800, rumours say that "Crutcher"
<cr******@gmail.com> might have written:
This seems great, except why can't I compare strings? It seems too
useful when dealing with user input, or parsing messages or config
files.
Weekdays = enum('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat')
Weekdays.mon.__cmp__('mon')

some_value = Weekdays.thu
....
user_input = raw_input("Enter day name")
if user_input == str(some_value):
Additionaly, perhaps the call method of the enumeration object should
construct a value from strings? Weekdays.mon == Weekdays('mon')


Either way works for me.
--
TZOTZIOY, I speak England very best.
"Dear Paul,
please stop spamming us."
The Corinthians
Mar 3 '06 #78

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.