Python functions with multiple parameter brackets
I've been having trouble understanding what h(a)(b)
means. I'd never seen one of those before yesterday, and I couldn't declare a function this way:
def f (a)(b):
return a(b)
When I tried to do def f (a, b):
, it didn't work either. What do these functions do? How can I declare them? And, finally, what's the difference between f(a, b)
and f(a)(b)
?
Functions with multiple parameter brackets don't exist, as you saw when you tried to define one. There are, however, functions which return (other) functions:
def func(a):
def func2(b):
return a + b
return func2
Now when you call func()
it returns the inner func2
function:
>>> func2 = func(1) # You don't have to call it func2 here
>>> func2(2)
3
But if you don't need the inner function later on, then there's no need to save it into a variable and you can just call them one after the other:
>>> func(1)(2) # func(1) returns func2 which is then called with (2)
3
This is a very common idiom when defining decorators that take arguments.
Notice that calling func()
always creates a new inner function, even though they're all named func2
inside of the definition of our func
:
>>> f1 = func(1)
>>> f2 = func(1)
>>> f1(1), f2(1)
(2, 2)
>>> f1 is f2
False
And, finally, what's the difference between
f(a, b)
andf(a)(b)
?
It should be clear now that you know what f(a)(b)
does, but to summarize:
-
f(a, b)
callsf
with two parametersa
andb
-
f(a)(b)
callsf
with one parametera
, which then returns another function, which is then called with one parameterb
f(a)(b)
just means that the expression f(a)
returns a value that is itself callable. It's a short form of
g = f(a)
g(b)
You might be more comfortable adding a pair of redundant parentheses to emphasize that this is not a single syntactic construct.
(f(a))(b) # f(a) is evaluated first, then the result is applied to b
It is exactly analogous to the same doubling of square brackets for indexing nested dictionaries.
d1[x][y]
is equivalent to
d2 = d1[x]
d2[y]
Lets say we have an expression like
f(a)(b)
then, f(a)
returns a function itself which gets invoked with argument b
. Consider the following example
def f(a):
def g(b):
return a * b
return g
Then f(5)(4)
evaluates to 5 * 4
, since f(5)
returns a function which is basically
def g(b):
return 5 * b
One could now do stuff like this
mult_by_5 = f(5)
[mult_by_5(x) for x in range(10)]
Let's be fancy, what about more nested functions?:
def f(a):
def g(b):
def h(c):
return a * b *c
return h
return g
f(2)(3)(4) # 24