What do you use as symbols for Python ?

32 views
Skip to first unread message

Pierre Barbier de Reuille

unread,
Nov 10, 2005, 2:37:19 AM11/10/05
to
When you need some symbols in your program, what do you use in Python ?

For example, an object get a state. This state is more readable if
expressed as a symbols, for example "opened", "closed", "error".
Typically, in C or C++, I would use an enum for that:
enum OBJECT_STATE
{
opened, closed, error
}

In CAML or Haskell I would use the union types:

type ObjectState = Opened | Closed | Error

In Ruby I would use the symbols :

object.state = :opened
object.state = :closed
object.state = :error

... but I don't know what to use in Python !

Thanks,

Pierre

Erik Max Francis

unread,
Nov 10, 2005, 2:40:59 AM11/10/05
to
Pierre Barbier de Reuille wrote:

> When you need some symbols in your program, what do you use in Python ?
>
> For example, an object get a state. This state is more readable if
> expressed as a symbols, for example "opened", "closed", "error".
> Typically, in C or C++, I would use an enum for that:
> enum OBJECT_STATE
> {
> opened, closed, error
> }

OPENED, CLOSED, ERROR = range(3)

object.state = OPENED

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
Whoever named it necking was a poor judge of anatomy.
-- Groucho Marx

George Sakkis

unread,
Nov 10, 2005, 3:45:58 AM11/10/05
to
"Erik Max Francis" <m...@alcyone.com> wrote:

> Pierre Barbier de Reuille wrote:
>
> > When you need some symbols in your program, what do you use in Python ?
> >
> > For example, an object get a state. This state is more readable if
> > expressed as a symbols, for example "opened", "closed", "error".
> > Typically, in C or C++, I would use an enum for that:
> > enum OBJECT_STATE
> > {
> > opened, closed, error
> > }
>
> OPENED, CLOSED, ERROR = range(3)
>
> object.state = OPENED

Or if you want something closer to real enumerations, there are several
recipes in the cookbook.
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413486 seems to
be pretty good according to the ratings.

George

bruno at modulix

unread,
Nov 10, 2005, 8:14:19 AM11/10/05
to
Pierre Barbier de Reuille wrote:

Depends on the job... If I need to do bitmask operations, I'll use
integer flags. If I want the symbol to be human-readable, I'll use
strings. But everything in Python being an object, you can use whatever
seems appropriate....

Since we're in a 'state' exemple, here's a possible state pattern
implementation:

class MyObject(object):
def __init__(self, name):
self.name = name
self.__class__ = ClosedState

state = property(fget=lambda self: self.__class__)

def open(self, arg):
if arg == 1:
self.__class__ = OpenedState
else:
self.__class__ = ErrorState

def close(self):
self.__class__ = ClosedState


class OpenedState(MyObject):pass
class ClosedState(MyObject):pass
class ErrorState(MyObject):pass

m = MyObject('toto')
assert m.state is ClosedState
m.open(1)
assert m.state is OpenedState
m.close()
assert m.state is ClosedState
m.open(2)
assert m.state is ErrorState

I made states 'dummy' objects, but you could make this a real state
pattern implementation by defining default methods in the base class and
overriding appropriate methods in the 'state' subclasses.

HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'on...@xiludom.gro'.split('@')])"

Antoon Pardon

unread,
Nov 10, 2005, 8:19:11 AM11/10/05
to
Op 2005-11-10, Pierre Barbier de Reuille schreef <pierre....@cirad.fr>:

I sometimes just use a class per symbol

class Opened: pass
class Closed: pass
class Error: pass

--
Antoon Pardon

Gary Herron

unread,
Nov 10, 2005, 12:27:14 PM11/10/05
to pytho...@python.org
Erik Max Francis wrote:

>Pierre Barbier de Reuille wrote:
>
>
>
>>When you need some symbols in your program, what do you use in Python ?
>>
>>For example, an object get a state. This state is more readable if
>>expressed as a symbols, for example "opened", "closed", "error".
>>Typically, in C or C++, I would use an enum for that:
>>enum OBJECT_STATE
>>{
>> opened, closed, error
>>}
>>
>>
>
> OPENED, CLOSED, ERROR = range(3)
>
> object.state = OPENED
>
>

Another similar approach that keeps those values together in a single
namespace is this (my favorite):

class State:


OPENED, CLOSED, ERROR = range(3)

Then you can refer to the values as
State.OPENED
State.CLOSED
State.ERROR

The extra clarity (and slight wordiness) of the dotted notation seems,
somehow, quite Pythonic to me.

Gary Herron

--
Gary Herron, PhD.
Department of Computer Science
DigiPen Institute of Technology
(425) 895-4418


Pierre Barbier de Reuille

unread,
Nov 10, 2005, 1:57:17 PM11/10/05
to
Well, thank you all !

I still feel it could be good for Python to have some kind of symbols
built in, and I will try to expose that to the python-dev list, to see
their reaction.

But in the different solutions proposed, the one I prefer is probably
the definitions of contants in a class to group them. Simple and
organized, I like it.

Thanks,

Pierre

Scott David Daniels

unread,
Nov 10, 2005, 3:01:37 PM11/10/05
to
Pierre Barbier de Reuille wrote:
A suggestion: There are enough PyDev-ers who read this list that you
needn't bother talking over there (it will be resented). If you want
to pursue it farther, either submit an RFE with a fairly thorough
explanation of why this is useful, or write and carry a PEP through
about it. This suggestion is neither new nor unique (many people
used to other languages suggest it as they come to Python), so you
probably will have to have quite persuasive arguments.

--Scott David Daniels
scott....@acm.org

Lonnie Princehouse

unread,
Nov 10, 2005, 3:11:06 PM11/10/05
to
I use custom classes and the "is" operator... that way, things don't
get confused with integers, and I have an object where repr(state) will
give me more than an integer. (the integer approach works well enough
but seems like a case of "I can program C in ANY language!")

opened = type('opened', (object,), {})
closed = type('closed', (object,), {})
error = type('closed', (object,), {})

if thing.state is opened:
...
elif thing.state is error:
... etc

Sion Arrowsmith

unread,
Nov 11, 2005, 9:27:44 AM11/11/05
to
Gary Herron <ghe...@digipen.edu> wrote:
>Another similar approach that keeps those values together in a single
>namespace is this (my favorite):
>
> class State:
> OPENED, CLOSED, ERROR = range(3)
>
>Then you can refer to the values as
> State.OPENED
> State.CLOSED
> State.ERROR
>
>The extra clarity (and slight wordiness) of the dotted notation seems,
>somehow, quite Pythonic to me.

I have here an implementation (written by a colleague) of a whole pile
of such -- in this particular case it's helpful to do it in this style
rather than the class OPENED: pass because the values are coming from/
going to a database. And it goes a little further, with

class State:
Enum = range(3)
OPENED, CLOSED, ERROR = Enum
Names = { OPENED: "OPENED", CLOSED: "CLOSED", ERROR: "ERROR" }

so you can used State.Names[state] to provide something user-readable,
and state in State.Enum to check data consistency. (OK, that probably
doesn't make much sense with this particular State, but it does when
your getting value-as-number from an external source.)

--
\S -- si...@chiark.greenend.org.uk -- http://www.chaos.org.uk/~sion/
___ | "Frankly I have no feelings towards penguins one way or the other"
\X/ | -- Arthur C. Clarke
her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump

Scott David Daniels

unread,
Nov 11, 2005, 12:48:24 PM11/11/05
to
Sion Arrowsmith wrote:
...

> class State:
> Enum = range(3)
> OPENED, CLOSED, ERROR = Enum
> Names = { OPENED: "OPENED", CLOSED: "CLOSED", ERROR: "ERROR" }

> so you can used State.Names[state] to provide something user-readable, ...

Or use a function like:

def named(value, classes):
for klass in classes:
for name, val in vars(klass).iteritems():
if val == value:
return name
raise ValueError, "No names for %r in %s" (value, classes)

Remember CPU time is almost free when it is associated with a line
typed to a user paying attention. This way you (A) don't have
to repeat the names in the source (a great place for errors),
and (B) you can say to yourself, "I think this is in one of these
several things" and go hunting happily.

In our example, named(2, [State]) gives us "ERROR"

--
-Scott David Daniels
scott....@acm.org

Daniel Evers

unread,
Nov 11, 2005, 1:26:16 PM11/11/05
to
Hi!

Never would have thought of this...
I mixed this with the class-version and created a new class derived from
"str" for easier printing and added an iterator:

---

class Enum:
class Type(str):
def __init__(self, name):
self.__name = name
def __str__(self):
return self.__name

def __init__(self, *keys):
self.__keys = []
for key in keys:
mytype = self.Type(key)
self.__dict__[key] = mytype
self.__keys.append(mytype)
self.__index = -1
self.__count = len(keys)

def __iter__(self):
return self

def next(self):
self.__index = self.__index + 1
if (self.__index >= self.__count):
self.__index = -1
raise StopIteration
return self.__keys[self.__index]

friends = Enum("Eric", "Kyle", "Stan", "Kenny")
print "These are my friends:",
print ", ".join([kid for kid in friends])
for kid in friends:
print kid,
if kid is friends.Kenny:
print "dead"
else:
print "alive"
---

Daniel

gsteff

unread,
Nov 11, 2005, 5:23:00 PM11/11/05
to
I've seen the following style in some code (the formencode library
comes to mind):

opened = object()
closed = object()
error = object()

Greg

Björn Lindström

unread,
Nov 11, 2005, 5:38:42 PM11/11/05
to
Gary Herron <ghe...@digipen.edu> writes:

> Another similar approach that keeps those values together in a single
> namespace is this (my favorite):
>
> class State:
> OPENED, CLOSED, ERROR = range(3)
>
> Then you can refer to the values as
> State.OPENED
> State.CLOSED
> State.ERROR

Of course, with this solution you still get this problem:

class State:
OPENED, CLOSED, ERROR = range(3)

class Spam:
EGGS, HAM, TOAST = range(3)

State.ERROR == Spam.TOAST => True

Thus, the solutions using unique objects for each value seems cleaner,
and closer to actual symbols, to me.

I don't see why Python doesn't go all the way and add a real symbol
type, though. I've seen way too many ugly string or integer based
solutions.

--
Björn Lindström <bk...@stp.lingfil.uu.se>
Student of computational linguistics, Uppsala University, Sweden

Peter Otten

unread,
Nov 12, 2005, 2:27:18 AM11/12/05
to
Daniel Evers wrote:

> I mixed this with the class-version and created a new class derived from
> "str" for easier printing and added an iterator:
>
> ---
>
> class Enum:
> class Type(str):
> def __init__(self, name):
> self.__name = name
> def __str__(self):
> return self.__name
>
> def __init__(self, *keys):
> self.__keys = []
> for key in keys:
> mytype = self.Type(key)
> self.__dict__[key] = mytype
> self.__keys.append(mytype)

You should ditch what follows and instead add just

def __iter__(self):
return iter(self.__keys)

> self.__index = -1
> self.__count = len(keys)
>
> def __iter__(self):
> return self
>
> def next(self):
> self.__index = self.__index + 1
> if (self.__index >= self.__count):
> self.__index = -1
> raise StopIteration
> return self.__keys[self.__index]
>
> friends = Enum("Eric", "Kyle", "Stan", "Kenny")
> print "These are my friends:",
> print ", ".join([kid for kid in friends])
> for kid in friends:
> print kid,
> if kid is friends.Kenny:
> print "dead"
> else:
> print "alive"
> ---

To see the problem with your original code (an object serving as its own
iterator) try the following example:

friends = Enum("Eric", "Kyle", "Stan", "Kenny")

if "Kyle" in friends:
print "Hi Kyle"
print "My friends:", ", ".join(friends)

Only Stan and Kenny show up in the last print statement because the
containment test did not iterate over all friends.

Also, Type.__name seems redundant. Just

class Type(str): pass

should do the job.

Peter

Chris Smith

unread,
Nov 12, 2005, 3:49:31 AM11/12/05
to
>>>>> "Gary" == Gary Herron <ghe...@digipen.edu> writes:

Gary> Erik Max Francis wrote:
>> Pierre Barbier de Reuille wrote: > > >
>>When you need some symbols in your program, what do you use in
>> Python ?
>>>
>>> For example, an object get a state. This state is more
>>> readable if expressed as a symbols, for example "opened",
>>> "closed", "error". Typically, in C or C++, I would use an
>>> enum for that: enum OBJECT_STATE { opened, closed, error
>>> }
>>>
>>>
>>
> OPENED, CLOSED, ERROR = range(3)
>>
>> object.state = OPENED
>>
>>

Gary> Another similar approach that keeps those values together in
Gary> a single namespace is this (my favorite):

Gary> class State: OPENED, CLOSED, ERROR = range(3)

Gary> Then you can refer to the values as State.OPENED
Gary> State.CLOSED State.ERROR

Gary> The extra clarity (and slight wordiness) of the dotted
Gary> notation seems, somehow, quite Pythonic to me.

Gary> Gary Herron

I think Zoran Isailovski has the last word on the topic:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413486

Daniel Evers

unread,
Nov 12, 2005, 10:52:57 AM11/12/05
to
Peter Otten wrote:
>
> You should ditch what follows and instead add just
>
> def __iter__(self):
> return iter(self.__keys)

Mhh. I should start learning the builtins ... :)

> To see the problem with your original code (an object serving as its own
> iterator) try the following example:
>
> friends = Enum("Eric", "Kyle", "Stan", "Kenny")
> if "Kyle" in friends:
> print "Hi Kyle"
> print "My friends:", ", ".join(friends)
>
> Only Stan and Kenny show up in the last print statement because the
> containment test did not iterate over all friends.

Never would have thought of this... Makes it even easier.

> Also, Type.__name seems redundant. Just
>
> class Type(str): pass
>
> should do the job.

Right, works just fine. I'm not used to types, meanwhile I replaced
Type(str) by a simple class Type, works as well.

Thanks a lot, I was starting to integrate this solution in my code, now I
can fix it before it's even used :)

Daniel

Reply all
Reply to author
Forward
0 new messages