What do you use as symbols for Python ?

  • Thread starter Pierre Barbier de Reuille
  • Start date
P

Pierre Barbier de Reuille

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 = :eek:pened
object.state = :closed
object.state = :error

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

Thanks,

Pierre
 
E

Erik Max Francis

Pierre said:
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
 
B

bruno at modulix

Pierre said:
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 = :eek:pened
object.state = :closed
object.state = :error

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

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
 
A

Antoon Pardon

Op 2005-11-10 said:
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 = :eek:pened
object.state = :closed
object.state = :error

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

I sometimes just use a class per symbol

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

Gary Herron

Erik said:
Pierre Barbier de Reuille wrote:




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
 
P

Pierre Barbier de Reuille

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
 
S

Scott David Daniels

Pierre said:
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
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
(e-mail address removed)
 
L

Lonnie Princehouse

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
 
S

Sion Arrowsmith

Gary Herron said:
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

Scott David Daniels

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"
 
D

Daniel Evers

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"
 
G

gsteff

I've seen the following style in some code (the formencode library
comes to mind):

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

Greg
 
G

Guest

Gary Herron said:
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.
 
P

Peter Otten

Daniel said:
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
 
C

Chris Smith

OPENED, CLOSED, ERROR = range(3)
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
 
D

Daniel Evers

Peter said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top