Dynamically create static variables (Enum hack)

I am trying to create a set of states for a class Node. I usually do this by setting each Nodeinstance variable stateto int, and a document that int matches what state (since I don't have enums).
This time I would like to try something else, so I decided to go with this:

class Node:
  state1 = 1
  state2 = 2

  def __init__(self):
    ...

It works well. However, I ran into a problem when I have many states - too many to print manually. Also, with these many states, I can make a mistake and assign the same to the inttwo states. This would be a source of error in testing conditions (for example, if self.state==Node.state1may fail if Node.state1and Node.state2were 3).

For this reason, I would like to do something like this:

class Node:
  def __init__(self):
    ...
...

for i,state in enumerate("state1 state2".split()):
  setattr(Node, state, i)

Although this would fix human errors in assigning values ​​to states, it is pretty ugly as class variables are set outside the class definition.

Is there a way to set class variables in a class definition this way? Ideally, I would like to do this:

class Node:
  for i,state in enumerate("state1 state2".split()):
    setattr(Node, state, i)

... but this will not work, as it Nodeis not yet defined, and will lead toNameError

Alternatively, does enumpython3.3 exist?

I'm on Python3.3.2 if that matters

+4
source share
5 answers

setattr , , ?

def add_constants(names):
    def adder(cls):
        for i, name in enumerate(names):
            setattr(cls, name, i)
        return cls
    return adder

@add_constants("state1 state2".split())
class Node:
    pass
+2

, Python Enum, . AutoEnum. - :

class Node:

    class State(AutoEnum):
        state1 = "initial state before blah"
        state2 = "after frobbing the glitz"
        state3 = "still needs the spam"
        state4 = "now good to go"
        state5 = "gone and went"

    vars().update(State.__members__)

:

--> Node.state2
<State.state2: 2>

: , Python 2.x - unicode, Python 3.x.

+3

enum34: Python 3.4 Enum backported

>>> import enum
>>> State = enum.IntEnum('State', 'state1 state2')
>>> State.state1
<State.state1: 1>
>>> State.state2
<State.state2: 2>
>>> int(State.state2)
2

AutoNumber Python 3.4:

>>> import enum
>>> class AutoNumber(enum.Enum):
...     def __new__(cls):
...         value = len(cls.__members__) + 1
...         obj = object.__new__(cls)
...         obj._value_ = value
...         return obj
... 
>>> class Node(AutoNumber):
...     state1 = ()
...     state2 = ()
... 
>>> Node.state1
<Node.state1: 1>
>>> Node.state2
<Node.state2: 2>
>>> Node.state2.value
2
+2

, , , 1 .

: http://docs.python.org/3.4/library/enum.html

:

class EnumMeta(type):
    def __new__(cls, name, bases, dict_):
        names = dict_.get('_enum_string', '')
        if names:
            for i, name in enumerate(names.split()):
                dict_[name] = 'foo %d' % i

        return super(EnumMeta, cls).__new__(cls, name, bases, dict_)


class Node(object):
    __metaclass__ = EnumMeta
    _enum_string = 'state1 state2'

print 'state1', SomeMeta.state1
print 'state2', SomeMeta.state2

( imho ):

class Node(object):
    pass

for i, state in enumerate('state1 state2'.split()):
    setattr(Node, state, i)
+1

? :

class Node:
    for i,state in enumerate("state1 state2".split()):
        setattr(Node, state, i)

... , Node , NameError

While the class does not yet exist, the namespace is used. It can be accessed with vars()(and also, I think locals()). This means you can do something like:

class Node:
    node_namespace = vars()
    for i, state in enumerate('state1 state2'.split()):
        node_namespace[state] = i
    del node_namespace
+1
source

All Articles