Reputation: 618
So I got this code:
class MyClass:
ACTIONS = {
"ACTION_A": MyClass.__a,
"ACTION_B": MyClass.__b
}
@staticmethod
def do(constant):
ACTIONS[constant]()
@staticmethod
def __a():
print("A")
@staticmethod
def __b():
print("B")
I'm trying to map the private __a and __b functions to a static dictionary so I'm able to execute functions with the method do.
When trying to run this code I get the error: "Unresolved reference 'MyClass'" on each line of the ACTIONS dictionary.
Any idea on how make this work properly?
Upvotes: 0
Views: 4253
Reputation: 1124238
You shouldn't be using a class in the first place. All you are doing is creating a namespace, use a module for that. Create a new module in a package and put all your functions in that:
def _a():
print("A")
def _b():
print("B")
ACTIONS = {
'ACTION_A': _a,
'ACTION_B': _b,
}
def do(constant):
ACTIONS[constant]()
Note that I used single underscore names. Python uses double-underscore names in classes to create an additional per-class namespace. MyClass.__a
becomes MyClass._MyClass__a
to avoid clashes with subclasses (so they can freely re-use names without fear of breaking the implentation of a superclass), there is no privacy model in Python.
You could use a decorator to register the _a
and _b
functions:
def do(constant):
ACTIONS[constant]()
ACTIONS = {}
def action(name):
def decorator(f):
ACTIONS[name] = f
return f
@action('ACTION_A')
def _a():
print("A")
@action('ACTION_B')
def _b()
print("B")
The specific error you see is due to the MyClass
name not being set until the whole class
statement has completed. You'd have to set that dictionary afterwards:
class MyClass:
@classmethod
def do(cls, constant):
cls.ACTIONS[constant]()
@staticmethod
def _a():
print("A")
@staticmethod
def _b():
print("B")
MyClass.ACTIONS = {
'ACTION_A': MyClass._a,
'ACTION_B': MyClass._b,
}
Note that do
is a class method, you can't just access ACTIONS
as a global, you need to use either MyClass.ACTIONS
or, as I used above, a class method then reference the object on cls
.
You could work around having to set ACTIONS
after the class
statement by using names instead, and make def do
a class method:
class MyClass:
ACTIONS = {
'ACTION_A': '_a',
'ACTION_B': '_b',
}
@classmethod
def do(cls, constant):
getattr(cls, cls.ACTIONS[constant])()
@staticmethod
def _a():
print("A")
@staticmethod
def _b():
print("B")
Upvotes: 5