Search code examples
pythonpython-3.xenumspython-3.3class-variables

Dynamically Create Static Variables (Enum hack)


I'm trying to create a set of states for a Node class. Normally, I would do this by setting each Node instance's state variable to an int, and document which int corresponds to which state (since I don't have enums).
This time, I'd like to try something different, so I decided to go with this:

class Node:
  state1 = 1
  state2 = 2

  def __init__(self):
    ...

This works well. However, I run into a problem where I have a LOT of states - too many to manually type out. Further, with that many states, I might make an error and assign the same int to two states. This would be a source of bugs when testing for states (e.g.: if self.state==Node.state1 might fail if Node.state1 and Node.state2 were both 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)

While this would fix human errors in assigning values to states, it's quite ugly, as class variables are being set outside the class definition.

Is there a way I could set class variables within the class definition in this manner? I would ideally like to do this:

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

... but that won't work as Node hasn't been defined yet, and will result in a NameError

Alternatively, do enums exist in python3.3?

I'm on Python3.3.2, if it matters


Solution

  • If your only problem with doing the setattr after the class definition is that it's ugly and in the wrong place, what about using a decorator to do it?

    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