This question already has an answer here:
- Function chaining in Python 5 answers
I am calculating a sum using lambda
like this:
def my_func(*args):
return reduce((lambda x, y: x + y), args)
my_func(1,2,3,4)
and its output is 10
.
But I want a lambda
function that takes random arguments and sums all of them. Suppose this is a lambda function:
add = lambda *args://code for adding all of args
someone should be able to call the add
function as:
add(5)(10) # it should output 15
add(1)(15)(20)(4) # it should output 40
That is, one should be able to supply arbitrary number of parenthesis.
Is this possible in Python?
You can kind of do this with a class, but I really wouldn't advise using this "party trick" in real code.
output
Initially,
add(1)
creates anadd
instance, setting its.args
attribute to 1.add(1)(15)
invokes the.call
method, adding 15 to the current value of.args
and returning the instance so we can call it again. This same process is repeated for the subsequent calls. Finally, when the instance is passed toprint
its__repr__
method is invoked, which passes the string representation of.args
back toprint
.The sort of "currying" you're looking for is not possible.
Imagine that
add(5)(10)
is 15. In that case,add(5)(10)(20)
needs to be equivalent to15(20)
. But 15 is not callable, and in particular is not the same thing as the "add 15" operation.You can certainly say
lambda *args: sum(args)
, but you would need to pass that its arguments in the usual way:add(5,10,20,93)
[EDITED to add:] There are languages in which functions with multiple arguments are handled in this sort of way; Haskell, for instance. But those are functions with a fixed number of multiple arguments, and the whole advantage of doing it that way is that if e.g.
add 3 4
is 7 thenadd 3
is a function that adds 3 to things -- which is exactly the behaviour you're wanting not to get, if you want something like this to take a variable number of arguments.For a function of fixed arity you can get Haskell-ish behaviour, though the syntax doesn't work so nicely in Python, just by nesting lambdas: after
add = lambda x: lambda y: x+y
you can sayadd(3)(4)
and get 7, or you can sayadd(3)
and get a function that adds 3 to things.[EDITED again to add:] As Ashwini Chaudhary's ingenious answer shows, you actually can kinda do what you want by arranging for
add(5)(10)
to be not the actual integer 15 but another object that very closely resembles 15 (and will just get displayed as 15 in most contexts). For me, this is firmly in the category of "neat tricks you should know about but never ever actually do", but if you have an application that really needs this sort of behaviour, that's one way to do it.(Why shouldn't you do this sort of thing? Mostly because it's brittle and liable to produce unexpected results in edge cases. For instance, what happens if you ask for
add(5)(10.5)
? That will fail with A.C.'s approach; PM 2Ring's approach will cope OK with that but has different problems; e.g.,add(2)(3)==5
will beFalse
. The other reason to avoid this sort of thing is because it's ingenious and rather obscure, and therefore liable to confuse other people reading your code. How much this matters depends on who else will be reading your code. I should add for the avoidance of doubt that I'm quite sure A.C. and PM2R are well aware of this, and that I think their answers are very clever and elegant; I am not criticizing them but offering a warning about what to do with what they've told you.)This is not possible with lambda, but it is definitely possible to do this is Python.
To achieve this behaviour you can subclass
int
and override its__call__
method to return a new instance of the same class with updated value each time:Demo:
If you want to support
float
s as well then subclass fromfloat
instead ofint
.