1

My question is some how related to this question, I have a dictionary of functions with a different number of arguments, how can I call them in an automatic way?

funcdict = {
  'mypackage.mymodule1.myfunction1': mypackage.mymodule.myfunction,
  'mypackage.mymodule2.myfunction2': mypackage.mymodul2.myfunctio2,
    ....
}

funcdict[0](parameter1, parameter2)
funcdict[1](parameter1, parameter2, parameter3)
funcdict[1](parameter1, parameter2, parameter3,parameter4,parameter5)
.........

Instead of calling each of them like above wanna something like this

for i in range(len(funcdict)):
     funcdict[i](......)

Don't know how should I fill the arguments since the number of arguments for each function varies between 2 to 6.

3
  • 1
    Well, what determines the number of parameters? If it's the function alone, maybe you should (a) store the number of params with the function in the dict or (b) rig/wrap the functions to all take the same number of parameters. Commented Mar 3, 2014 at 22:09
  • 1
    functdict is a dictionary, but you're using it like a list. Is this intentional? Am I missing something? Commented Mar 3, 2014 at 22:20
  • @crennie I just follow this question stackoverflow.com/questions/2283210/python-function-pointer maybe something is wrong I am not using the code I wrote above I just want to find the solution for calling different function with different number of arguments. Commented Mar 3, 2014 at 22:25

3 Answers 3

2

If you want to call all your functions in an automatic way, specifically, all at once, then it isn't important that you be able to call them by some specific name like it was in the question you are referencing. You can just keep the functions in a list and call each one in turn.

As for dealing with a variable number of arguments, Python has a "splat" operator you may have seen in some method declarations: def __init__(self, *args, **kwargs). This operator can be used to unpack argument lists. (See this SO answer for more info)

If you store the parameters in another list you can iterate through your list of functions and apply the parameters to its corresponding function one-by-one using the same syntax and without specifying the number of arguments:

funclist = [lambda x,y: x+y, lambda x,y,z: x+y+z, lambda x: -x]
paramlist = [(1,2), (1,2,3), (1,)]

for index, func in enumerate(funclist):
    print func(*paramlist[index])

How you link the functions to their default parameters is another matter: you could keep them in two lists, or together as tuples in another list or dict, or define a lightweight class to hold them...it depends on your problem. Anyways, it sounds like the important part for you is the * notation.

Edit:

If you want to pass in keyword arguments to the function, you can use the double-* notation to pass a dictionary and have it expanded into the keyword arguments that are required:

def func1(n_samples, noise, factor, random_state):
    print locals()

def func2(n_samples, ratio, noise):
    print locals()

def func3(my_key, default_key='world!'):
    print locals()

funclist = [func1, func2, func3]
paramlist = [
        dict(
            n_samples=1000,
            noise=0.3,
            factor=0.5,
            random_state=1
        ),
        dict(
            n_samples=1000,
            ratio=0.5,
            noise=0.1
        ),
        dict(
            my_key='hello',
        )
]

for index, func in enumerate(funclist):
    func(**paramlist[index])
Sign up to request clarification or add additional context in comments.

2 Comments

Actually that's a very good solution thank you but I have a little problem for the arguments my arguments are like these, for first function (n_samples = 1000, noise=0.3, factor=0.5, random_state=1) for second one (n_samples = 1000, ratio = 0.5, noise = 0.1) and if I want to create a list like yours for my arguments it gives me an error and I can not eliminate the left part of argumnts (I mean n_samples, ratio and ..) cause the order of arguments are important do you have any solution for this?
I added an edit about keyword arguments. Is this what you were after?
1

OK, let's suppose that you put your arguments in a tuple. You will also need to refine your table so you know how many arguments each function takes, which means a modification of your data structure (you could use the inspect module to determine this, but that's an unnecessary complication at present.:

If the functions have to be called an any specific order, by the way, a dict is not a good structure to use because it linearizes in an unpredictable order, but we'll overlook that for now. Here's a chunk of code that uses * notation to pass a tuple as individual arguments. I am using a reporter function to show you have the argument transmission works.

parameters = ("one", "two", "three", "four", "five")

def reporter(*args):
    print("Called with", len(args), "arguments")
    print("args are:", args)

funcdict = {
  'mypackage.mymodule1.myfunction1': (reporter, 1),
  'mypackage.mymodule2.myfunction2': (reporter, 5),
}

for name, (function, arg_ct) in funcdict.items():
    print("Testing", name)
    function(*parameters[:arg_ct])

The output is:

Testing mypackage.mymodule1.myfunction1
Called with 1 arguments
args are: ('one',)
Testing mypackage.mymodule2.myfunction2
Called with 5 arguments
args are: ('one', 'two', 'three', 'four', 'five')

I hope that gives you plenty to chew on.

Comments

0

As a first possibility, one could try to use the code object for the function by getting the func_code property then query co_argcount of this code object.

Here is a small example that calls the functions stored in a dictionary by name, for a set of input arguments, 2, 3, 4 in this case:

#!/usr/bin/env python

def f1(a, b):
    print "executing f1 with %d, %d" % (a, b)
    return a*b

def f2(a, b, c):
    print "executing f2 with %d, %d, %d" % (a, b, c)
    return a*b+c

def call_functions(arg1, arg2, arg3):
    funcdict = {
        "add" : f1,
        "madd" : f2
        }
    for f in funcdict.itervalues():
        if f.func_code.co_argcount == 2:
            f(arg1, arg2)
        elif f.func_code.co_argcount == 3:
            f(arg1, arg2, arg3)
        # and so on

if __name__=="__main__":
    call_functions(2, 3, 4)

Another slightly less verbose possibility (you don't need to explicitely check for the number of arguments for each function, the functions just use what they need) is to use Python's variable argument syntax. This would look as follows:

#!/usr/bin/env python

def f1(*args):
    print "executing f1 with %d, %d" % (args[0], args[1])
    return args[0]*args[1]

def f2(*args):
    print "executing f2 with %d, %d, %d" % (args[0], args[1], args[2])
    return args[0]*args[1]+args[2]

def call_functions(*args):
    funcdict = {
        "add" : f1,
        "madd" : f2
        }
    for f in funcdict.itervalues():
        f(*args)

if __name__=="__main__":
    call_functions(2, 3, 4)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.