Paul Brink
Paul Brink

Reputation: 464

Calling functions and passing arguments in a more efficient way

My questions is basically how I can take a piece of code and optimize it to be more dynamic.

Firstly let me show how I am currently doing this.

Lets say I have a list of arguments like this:

argument_list = [['some_function', ['first', 'second'], 1, 2], ['another_function', ['first'], 3, 1, 5]]

Each of these sets of arguments correspond to a specific function to be called. Here are the two functions:

def some_function(number, a, b):
    print(number)
    print(a+b)


def another_function(number, c, d, e):
    print(number)
    print(c+d+e)

In the argument list, there is another list containing names such as "first", "second" and so on. For each of these names, the function should be called again, but only with the next name.

Currently I am doing it with a tedious loop like this:

for i in range(len(argument_list)):
    for j in range(len(argument_list[i][1])):
        if(argument_list[i][0] == 'some_function'):
            some_function(argument_list[i][1][j], argument_list[i][2], argument_list[i][3])
        if(argument_list[i][0] == 'another_function'):
            another_function(argument_list[i][1][j], argument_list[i][2], argument_list[i][3], argument_list[i][4])

As the list of arguments grows and new functions are added, it becomes a problem to add new if conditions and add the arguments manually.

My question is then, is there a way to dynamically identify which function should be called, and furthermore pass all of the arguments as a single object so that they can be evaluated in the function itself.

I read about unpacking arguments in the Python documentation, but I could not get it working with this example.

My idea is basically something like this:

argument_list = [{'function':'some_function', 'names':['first', 'second'], 'a':1, 'b':2}, {'function':'another_function', 'names':['first'], 'c':3, 'd':1, 'e':5}]


def some_function(param):
    print(param.name)
    print(param.a + param.b)


def another_function(param):
    print(param.name)
    print(param.c + param.d + param.e) 



for arguments in argument_list:
    #How to call the correct function here while iterating name
    #some_function(arguments) or another_function(arguments)

Also, if there are any suggestions on a better question title it would be great :)

Upvotes: 1

Views: 136

Answers (2)

cards
cards

Reputation: 4975

...you are in the right way to understand the general purpose decorators, *args, **kwargs! I will try to give a direction to start...

First don't over complicate the problem and forget for a moment the repetitions of the functions. Then redesign your argument_list maybe as:

[{'f': function1, 'args': [list of its args], 'kwargs': {dictionary of keywords parameters}}, ...].

A (not elegant at all) working example

argument_list = [{'function':'some_function', 'names':['first', 'second'], 'args': [1, 2, 3] } , {'function':'another_function', 'names':['first'], 'args': [9, 8, 7]}]


def some_function(number, a, b, e):
    print(number)
    print(a+b)


def another_function(number, c, d, e):
    print(number)
    print(c+d+e)


for f in argument_list:
    func = eval(f['function']) # execute the string as it were a python cmd
    args = f['args']

    func(0, *args)

Output

0
3
0
24

Remark if you define argument_list after the declaration of the last function then you can add the function name directly instead of the string counterpart and this avoid to use eval

Upvotes: 0

Maurice Meyer
Maurice Meyer

Reputation: 18106

You can make use of argument (un)packing:

argument_list = [
    ['some_function', ['first', 'second'], 1, 2],
    ['another_function', ['first'], 3, 1, 5]
]

def some_function(number, a, b):
    print(number)
    print(a + b)


def another_function(number, c, d, e):
    print(number)
    print(c + d + e)


for a in argument_list:
    fnName = a[0]
    a = a[1:]
    fn = globals().get(fnName)(*a)  # Look for the function string name in global scope

It might be easier to use function references:

argument_list = [
    [some_function, ['first', 'second'], 1, 2],
    [another_function, ['first'], 3, 1, 5]
]

for a in argument_list:
    fn = a[0]
    a = a[1:]
    fn(*a)

Out:

['first', 'second']
3
['first']
9

Upvotes: 1

Related Questions