3

Javascript has a poorly constructed but convenient "arguments" variable inside every function, such that you can pass arguments through a function like so:

function foo(a, b, c) {
    return bar.apply(this, arguments);
}
function bar(a, b, c) {
    return [a, b, c];
}
foo(2, 3, 5);    // returns [2, 3, 5]

Is there an easy way to do a similar thing in Python?

futuraprime
  • 5,468
  • 7
  • 38
  • 58

4 Answers4

4
>>> def foo(*args):
...     return args

>>> foo(1,2,3)
(1,2,3)

is that what you want?

andrew cooke
  • 45,717
  • 10
  • 93
  • 143
  • Python's `*args` functionality behaves the way that `spread` and `rest` are anticipated for the next Javascript standardization. – Karl Knechtel Mar 29 '12 at 00:40
  • 2
    also for keyword agruments of the style `foo(a=1, b=2)` you can capture them using the `**` keyword expansion: `foo(**kwargs)` which gives you kwargs as a `dict` and any dict can be sent to another function as keyword arguments via `bar(**kwargs)` – Preet Kukreti Mar 29 '12 at 01:04
  • you can also mix+match: `foo(a, b, *args)` or `foo(a, b=None, **kargs)` or even, in python 3, `foo(a, b, *args, c=None, **kargs)` – andrew cooke Mar 29 '12 at 01:08
2

How about using * for argument expansion?

>>> def foo(*args):
...     return bar(*(args[:3]))
>>> def bar(a, b, c):
...     return [a, b, c]
>>> foo(1, 2, 3, 4)
[1, 2, 3]
Nolen Royalty
  • 18,415
  • 4
  • 40
  • 50
  • This is nearly what I want, but I would have to use *args in the definition—I can't do: `def foo(a, b, c): return bar(*(args[:3]))` – futuraprime Mar 29 '12 at 00:45
  • The only thing that I can think of is using `locals()` in foo. `locals().values()` would give you all of the args passed to foo but they wouldn't be in a consistent order. – Nolen Royalty Mar 29 '12 at 02:01
  • @futuraprime Actually, scratch that. They would be in a consistent order based on the names of the arguments(that is to say, as long as your args were named a, b, and c their values would come out in the same order). However, in the case of "a, b, c" you get the values in the order "a, c, b". Doesn't seem like this is worth the trouble. – Nolen Royalty Mar 29 '12 at 02:20
2

Yeah, this is what I should have said.

def foo(*args):
    return bar(*args)

You don't need to declare the function with (a,b,c). bar(...) will get whatever foo(...) gets.

My other crummier answer is below:


I was so close to answering "No, it can't easily be done" but with a few extra lines, I think it can. @cbrauchli great idea using locals(), but since locals() also returns local variables, if we do

def foo(a,b,c):
    n = "foobar" # any code that declares local variables will affect locals()
    return bar(**locals())

we'll be passing an unwanted 4th argument, n, to bar(a,b,c) and we'll get an error. To solve this, you'd want to do something like arguments = locals() in the very first line i.e.

def foo(a, b, c):
    myargs = locals() # at this point, locals only has a,b,c
    total = a + b + c # we can do what we like until the end
    return bar(**myargs) # turn the dictionary of a,b,c into a keyword list using **
pagga
  • 171
  • 8
1

I think this most closely resembles your javascript snippet. It doesn't require you to change the function definition.

>>> def foo(a, b, c):
...   return bar(**locals())
... 
>>> def bar(a, b, c):
...   return [a, b, c]
... 
>>> foo(2,3,5)
[2, 3, 5]

Note that locals() gets all of the local variables, so you should use it at the beginning of the method and make a copy of the dictionary it produces if you declare other variables. Or you can use the inspect module as explained in this SO post.

Community
  • 1
  • 1
cbrauchli
  • 1,555
  • 15
  • 25