Zhurik
Zhurik

Reputation: 166

How to use dict in class as switch statement

I'm trying to use dict as a switch statement in python class like this:

class MyClass:
    METHODS_MAP = {}  # I want to place map here

    # some code here
    def caller(self, instructions):
        methods_map = {
            "a": self.a,
            "b": self.b
        }
        for key, value in instructions.items():
            methods_map[key](value)

    def a(self, val):
        print("Called a")

    def b(self, val):
        print("Called b")


a = MyClass()
instr = {"b": 12, "a": 14}
a.caller(instr)

Right now it works just fine, but I need to place methods_map at the same level as method definitions as static variable as some might say. I tried this:

class MyClass:
    METHODS_MAP = {
        "a": self.a
   }

or

class MyClass:
    METHODS_MAP = {
        "a": a
   }

But either way, it doesn't know about class methods. How can I make it work my way?

Upvotes: 0

Views: 164

Answers (2)

Gal
Gal

Reputation: 504

In order to reference methods implemented inside a class the following syntax is required:

METHODS_MAP = 
{
    'a': MyClass.a,
    'b': MyClass.b
}

Because some functions work on class instances and are not @classmethods, we need to change the caller() function:

from inspect import ismethod

def caller(self, instructions):
    for key, value in instructions.items():
        if METHODS_MAP[key].__self__ is MyClass: # check if function is class method
            METHODS_MAP[key](MyClass, value)
        elif ismethod(METHODS_MAP[key]): # check if method is an instance method
            METHODS_MAP[key](self, value)
        else: # static method
            METHODS_MAP[key](value)

If the desired function is not a @classmethod, self will be passed to it. Else, it will be called as usual

Important note: Although this solution seems more complex than initializing the MEHTODS_MAP dictionary inside the __init__() function, it is far less costly. With this method, the number of instances this class has does not affect the number of times METHODS_MAP will be created in memory (there will always be just one).

With the other method suggested here (using __init__()), for every instance of MyClass() a copy of METHODS_MAP will be needlessly created, since it is initialized inside the __init__() function

Upvotes: 0

ParthS007
ParthS007

Reputation: 2689

You can add them in the constructor like this:

class MyClass:
    def __init__(self):
        self.methods_map = {
            "a": self.a,
            "b": self.b
        }

    def caller(self, instructions):
        for key, value in instructions.items():
            self.methods_map[key](value)

    def a(self, val):
        print("Called a")

    def b(self, val):
        print("Called b")


x = MyClass()
instr = {"b": 12, "a": 14}
x.caller(instr)

Upvotes: 1

Related Questions