Search code examples
pythondecorator

using decorator arguments for switching


At the flaks library, we can use decorator like switch case. (Did I understand well?)

app.route('')

So...I would like to make some switch statement with decorators and arguments,

like:

@color('pink')
def _pink_power(self):
    print("wow")

@color('blue')
@color('red')
def _powerpower(self):
    print("god!!!!")

def input(color):
    I don't know what to do in here..
    if color is pink, print wow!

I was struggling to figure out this quite a long time, but I couldn't make it. Is it impossible do you think?


Solution

  • Here's a relatively simple way to do it (although I recommend that you change the name of the input function at the end because it conflicts with a built-in of the same name):

    class color:
        _func_map = {}
    
        def __init__(self, case):
            self.case = case
    
        def __call__(self, f):
            self._func_map[self.case] = f
            return f
    
        @classmethod
        def switch(cls, case):
            cls._func_map[case]()
    
    
    @color('pink')
    def _pink_power():
        print("wow")
    
    @color('blue')
    @color('red')
    def _powerpower():
        print("god!!!!")
    
    
    def input(colorname):
        color.switch(colorname)
    
    input('pink') # -> wow
    input('blue') # -> god!!!!
    input('red')  # -> god!!!!
    

    Enhancement

    You could support having a default case like C/C++'s switch statements support that will be used when there's no matching colorname:

    class color:
        DEFAULT = '_DEFAULT'
        _func_map = {}
    
        def __init__(self, case):
            self.case = case
    
        def __call__(self, f):
            self._func_map[self.case] = f
            return f
    
        @classmethod
        def _default(cls):
            raise ValueError('Unknown color!')
    
        @classmethod
        def switch(cls, case):
            cls._func_map.get(case, cls._default)()
    

    The _default() method added to the class raises an exception when it's invoked:

    input('lavender')  # -> ValueError: Unknown color!
    

    However you can override that by defining your own error-handler function:

    @color(color.DEFAULT)  # Override default function.
    def my_default():
        print("loser!")
    
    input('lavender')  # -> loser!