Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 625
inspectorG4dget Avatar asked Jan 11 '23 22:01

inspectorG4dget


1 Answers

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
like image 110
abarnert Avatar answered Jan 25 '23 10:01

abarnert