Skip to content Skip to sidebar Skip to footer

Can Lambda Work With *args As Its Parameter?

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 functi

Solution 1:

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:

classAdd(int):
    def__call__(self, val):
        returntype(self)(self + val)

Demo:

>>> Add(5)(10)
15
>>> Add(5)(10)(15)
30
>>> Add(5)
5
# Can be used to perform other arithmetic operations as well
>>> Add(5)(10)(15) * 1003000

If you want to support floats as well then subclass from float instead of int.

Solution 2:

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 to 15(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 then add 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 say add(3)(4) and get 7, or you can say add(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 be False. 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.)

Solution 3:

You can kind of do this with a class, but I really wouldn't advise using this "party trick" in real code.

class add(object):
    def __init__(self, arg):
        self.arg = arg

    def __call__(self, arg):
        self.arg += argreturnself

    def __repr__(self):
        return repr(self.arg)

# Test
print(add(1)(15)(20)(4))    

output

40 

Initially, add(1) creates an add 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 to print its __repr__ method is invoked, which passes the string representation of .args back to print.

Post a Comment for "Can Lambda Work With *args As Its Parameter?"