Passing all arguments of a function to another function
Asked Answered
H

4

96

I want to pass all the arguments passed to a function(func1) as arguments to another function(func2) inside func1 This can be done with *args, *kwargs in the called func1 and passing them down to func2, but is there another way?

Originally

def func1(*args, **kwargs):
    func2(*args, **kwargs)

but if my func1 signature is

def func1(a=1, b=2, c=3):

how do I send them all to func2, without using

def func1(a=1, b=2, c=3):
    func2(a, b, c)

Is there a way as in javascript callee.arguments?

Hexahydrate answered 28/6, 2010 at 23:41 Comment(6)
possibly related: #1137173Insole
I don't see how this could be useful...Poor
it's not all that useful, but sometimes I write a function with lot of args, and and bored of copying them over and over.Hexahydrate
@Mark no, not related, but thanks anyway.Hexahydrate
@Poor this is useful when writing generic decorators that do not care about function argsBalsaminaceous
@Poor - or if you're extracting common functionality to another function, and you don't what to change the existing external calling interfaceJahncke
S
75

Explicit is better than implicit but if you really don't want to type a few characters:

def func1(a=1, b=2, c=3):
    func2(**locals())

locals() are all local variables, so you can't set any extra vars before calling func2 or they will get passed too.

Shupe answered 29/6, 2010 at 0:7 Comment(8)
This will have the flaw that if you've created local variables before calling func2, then they will also be passed to func2.Gynecium
maybe you could copy locals right at the beginning of the function?Alternation
Now I remember reading about locals. I was thinking too much about vars() and couldn't remember locals(). Should have read the documents. I guess vars() can be used too.Hexahydrate
This would not work for class functions as it will get multiple values for selfRisibility
@Bhaskar: Is there any way around that?Witchcraft
@Bhaskar, can you elaborate on the problem? I'm only seeing one copy of self, even when using multiple inheritance. What's the "this" that won't work, using locals() at all, or trying to save a copy of the result as a way to have a record after a local variable has been created?Kostival
Ouch, I hate this one. The reason is that locals() is the wrong concept - you want to pass "all the parameters" not "all the local variables". All sorts of innocent changes - like adding a local variable before this line, or moving a function to be a method or vice versa - can break this code. More, the reader has to scratch their head to figure it out.Angular
Is there a lean general solution to pass mixed parameters from arguments and keyword arguments?Kinnikinnick
R
13

Provided that the arguments to func1 are only keyword arguments, you could do this:

def func1(a=1, b=2, c=3):
    func2(**locals())
Rotogravure answered 29/6, 2010 at 0:22 Comment(1)
Why only keyword arguments?Horodko
S
9

As others have said, using locals() might cause you to pass on more variables than intended, if func1() creates new variables before calling func2().

This is can be circumvented by calling locals() as the first thing and creating a copy of its contents, like so:

def func1(a=1, b=2,c=3):
    parameters = locals().copy()

    d = parameters ["a"] + parameters ["b"]

    func2(**parameters) #the value of `d` is not passed to func2.

If we had made the function call like func2(**locals()) then d would have been added as a parameter.

Setsukosett answered 21/11, 2019 at 9:6 Comment(1)
This doesn't work as intended, because parameters is a reference to locals() and will always show the same contents. The call to func2 will have both parameters and d as arguments. To use this method, you have to change the first line in the function to parameters = locals().copy(). This gets a copy of the initial locals() contents and remains constant as long as you don't modify the arguments themselves.Gastrology
D
0

For the sake of completeness, because this took me some time: the function lvl1 will consume var_a and var_b. Those variables will be removed from kwargs and will not be available to function lvl2 unless we copy them from locals and add them back to kwargs using the update method:

def lvl1(*, var_a, var_b, **kwargs):
    """Will print var_a, var_b and then call lvl2."""
    parameters = locals().copy()
    # right now var_a and var_b were consumed
    # and are not present within kwargs anymore
    # therefore the call to lvl2 function, which needs var_b, will fail
    # thats why we need to catch them from locals
    # and add back to kwargs
    kwargs.update(parameters)
    print(var_a)
    print(var_b)
    lvl2(**kwargs)

def lvl2(*, var_b, var_c, **kwargs):
    """Will print var_b, and var_c."""
    print(var_b)
    print(var_c)

# kwargs definition, we can name it anything
settings = {'var_a': 1, 'var_b': 2, 'var_c': 3}
# function call
lvl1(**settings)

This is specially useful in pipelines that call a lot of functions (lvl2) and we want to avoid repeating all those variable names on all function calls.

Distinctive answered 12/1 at 18:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.