Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling functions with parameters using a dictionary in Python

I'm making a program which has a main menu that asks the user to input an option and store it in integer option1, which is looked up in dictionary options. The corresponding function is then run. The following code works if the functions have no parameters:

options = {0 : FunctionZero,    # Assign functions to the dictionary
            1 : FunctionOne,
            2 : FunctionTwo,
            3 : FunctionThree}

options[option1]()    # Call the function

If the functions have parameters the above code doesn't work as the () part assumes the functions have no parameters, but I tried the following, which stores the functions' names and parameters in tuples within the dictionary:

options = {0 : (FunctionZero,""),    # FunctionsZero, FunctionOne
            1 : (FunctionOne,""),    # and FunctionTwo have no parameters
            2 : (FunctionTwo,""),
            3 : (FunctionThree,True)}    # FunctionThree has one parameter

if options[option1][1] == "":    # Call the function
    options[option1][0]()
else:
    options[option1][0](options[option1][1])

This code seems to work fine, but I was wondering if there's a better way to do this, especially if the functions require several parameters? In other languages like C# I'd probably use a switch or case statement (which is not in Python) and I'm avoiding using if...elif statements for this.

like image 662
Ruben9922 Avatar asked Jul 04 '14 21:07

Ruben9922


People also ask

How do you pass a dictionary as a parameter in Python?

Passing Dictionary as kwargs “ kwargs ” stands for keyword arguments. It is used for passing advanced data objects like dictionaries to a function because in such functions one doesn't have a clue about the number of arguments, hence data passed is be dealt properly by adding “**” to the passing type.

Can Python dictionary hold functions?

Dictionaries in Python Almost any type of value can be used as a dictionary key in Python. You can even use built-in objects like types and functions.

How do you pass the dictionary as Kwargs?

Inside the function, the kwargs argument is a dictionary that contains all keyword arguments as its name-value pairs. Precede double stars ( ** ) to a dictionary argument to pass it to **kwargs parameter. Always place the **kwargs parameter at the end of the parameter list, or you'll get an error.


3 Answers

I would do this using functools.partial to specify the arguments when the dictionary is created:

from functools import partial

options = {0: FunctionZero,   
           1: FunctionOne,    
           2: FunctionTwo,
           3: partial(FunctionThree, True)} 

Note that this also allows additional parameters to be passed when the function is called (as long as all the functions in the dictionary have the same parameters missing after partial has been called):

def test(one, two, three=None, four=None):
    ...

def test2(one, two, three=None):
    ...

options = {1: partial(test, 1, three=3, four=4),
           2: partial(test2, 1, three=3)}

...

options[choice](2) # pass the 'two' argument both functions still require
like image 152
jonrsharpe Avatar answered Sep 23 '22 19:09

jonrsharpe


Sure. In Python, functions can take positional or keyword arguments. For most functions, arguments can be passed in either way, but that’s not necessarily the case for all functions, so we do need to keep them separate. Positional arguments are in an iterable (often list or tuple), and keyword arguments are in a dictionary from strings to values.

We could then represent each function as a tuple of function, positional arguments, and keyword arguments:

options = {
    0: (function_zero, [], {}),
    1: (function_one, [], {}),
    2: (function_two, [], {}),
    3: (function_three, [True], {}),
    4: (function_four, [], {'kwarg': True}),  # takes a keyword argument
}

Then you could call them like this:

func, args, kwargs = options[option1]
func(*args, **kwargs)

But if you’re always going to just pass in a constant, there’s a better way: just create little no-argument wrappers for each function that call the function how you want it to be called:

options = {
    0: function_zero,
    1: function_one,
    2: function_two,
    3: lambda: function_three(True),
    4: lambda: function_four(kwarg=True),
}

Then use your first method:

options[option1]()

As detailed in jonrsharpe’s answer, you can also use functools.partial rather than a lambda. As he notes, this has the advantage of being able to append some of your own arguments:

options[option1]('hello')  # adds 'hello' to previously-specified arguments

If you don’t need this functionality, though, a zero-parameter lambda will serve you just fine.

like image 33
icktoofay Avatar answered Sep 23 '22 19:09

icktoofay


To add to icktoofay's answer, if you want to pass an argument to the lambda just do the following:

def printDouble( number ):
    print number * 2

options = {
    1: lambda num: printDouble(num)
}

options[1](4)    #this prints 8

By adding the parameter for lambda before the ":" you state that the lambda receives a parameter and it is used then in the function it calls.

Also if you don't want to use lambdas you can use the usual way

def printDouble( num ):
    print num * 2

def printHalf( num ):
    print half / 2

functionDictionary = {
    'Double': printDouble,
    'Half'  : printHalf
}

functionDictionary['Double'](2)    #This prints 4
like image 30
Xirion11 Avatar answered Sep 22 '22 19:09

Xirion11