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
> 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
> 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
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('@')])"
I sometimes just use a class per symbol
class Opened: pass
class Closed: pass
class Error: pass
--
Antoon Pardon
>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
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
scott....@acm.org
opened = type('opened', (object,), {})
closed = type('closed', (object,), {})
error = type('closed', (object,), {})
if thing.state is opened:
...
elif thing.state is error:
... etc
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
> 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
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
opened = object()
closed = object()
error = object()
Greg
> 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
> 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
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
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