Reputation: 464
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
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
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