Python replacement of switch case into dictionary (for function calls)

Question:

I’m trying to experiment with a replacement for switch/cases in Python that I had found online. It works quite well for most variables but I’m trying to make it such that I can call functions but I’m getting some strange behavior.

This is my python function using discord py:

async def reminder(self, ctx, *args): #args is the input from the user
     reminder_operations = {
            'add': await self.reminder_add(ctx),
            'modify': await self.reminder_modify(ctx),
            'delete': await self.reminder_delete(ctx),
            'deleteall': await self.reminder_delete_all(ctx)
        }
     reminder_operations[args[0]] # in this test, args[0] = 'add'

In this snippet above, every function in the dictionary is called.

reminder_operations = {
            'add': self.reminder_add(ctx),
            'modify': self.reminder_modify(ctx),
            'delete': self.reminder_delete(ctx),
            'deleteall': self.reminder_delete_all(ctx)
        }
        await reminder_operations[args[0]]

In this snippet above, it works (only self.reminder_add() is called) but pycharm throws a RuntimeWarning:

RuntimeWarning: coroutine 'reminder_cog.reminder_modify' was never awaited
  ret = await coro(*args, **kwargs)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
D:DownloadsAnacondalibsite-packagesdiscordextcommandscore.py:85: RuntimeWarning: coroutine 'reminder_cog.reminder_delete' was never awaited
  ret = await coro(*args, **kwargs)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
D:DownloadsAnacondalibsite-packagesdiscordextcommandscore.py:85: RuntimeWarning: coroutine 'reminder_cog.reminder_delete_all' was never awaited
  ret = await coro(*args, **kwargs)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

Should I just ignore these warnings? Is there a better way to go about dictionary switch-cases for functions?

Asked By: Sergio N.

||

Answers:

You are calling all of the functions (without await) when defining the dictionary and storing their return values in the dictionary instead of references to the functions.

async def reminder(self, ctx, *args):    
    reminder_operations = {
                    'add': self.reminder_add,
                    'modify': self.reminder_modify,
                    'delete': self.reminder_delete,
                    'deleteall': self.reminder_delete_all
                }
        
    return await reminder_operations[args[0]](ctx)
Answered By: Amit Eyal

I suggest you to await only the function that you want to call. This way only the function corresponding to the argument is actually executed, while in your code all the calls are executed. You need to modify your code the following way.

async def reminder(self, ctx, *args): #args is the input from the user
     reminder_operations = {
            'add': self.reminder_add,
            'modify': self.reminder_modify,
            'delete': self.reminder_delete,
            'deleteall': self.reminder_delete_all
        }
     await reminder_operations[args[0]](ctx)
Answered By: AndrejH