38

Is it possible a lambda function to have variable number of arguments? For example, I want to write a metaclass, which creates a method for every method of some other class and this newly created method returns the opposite value of the original method and has the same number of arguments. And I want to do this with lambda function. How to pass the arguments? Is it possible?

class Negate(type): def __new__(mcs, name, bases, _dict): extended_dict = _dict.copy() for (k, v) in _dict.items(): if hasattr(v, '__call__'): extended_dict["not_" + k] = lambda s, *args, **kw: not v(s, *args, **kw) return type.__new__(mcs, name, bases, extended_dict) class P(metaclass=Negate): def __init__(self, a): self.a = a def yes(self): return True def maybe(self, you_can_chose): return you_can_chose 

But the result is totally wrong:

>>>p = P(0) >>>p.yes() True >>>p.not_yes() # should be False Traceback (most recent call last): File "<pyshell#150>", line 1, in <module> p.not_yes() File "C:\Users\Desktop\p.py", line 51, in <lambda> extended_dict["not_" + k] = lambda s, *args, **kw: not v(s, *args, **kw) TypeError: __init__() takes exactly 2 positional arguments (1 given) >>>p.maybe(True) True >>>p.not_maybe(True) #should be False True 

3 Answers 3

43

There is no problem using varargs in lambda functions. The issue here is different:

The problem is that the the lambda refrences the loop variable v. But by the time the lambda is called, the value of v has changed and the lambda calls the wrong function. This is always something to watch out for when you define a lambda in a loop.

You can fix this by creating an additional function which will hold the value of v in a closure:

def create_not_function(v): return lambda s, *args, **kw: not v(s, *args, **kw) for (k, v) in _dict.items(): if hasattr(v, '__call__'): extended_dict["not_" + k] = create_not_function(v) 
Sign up to request clarification or add additional context in comments.

Comments

39

Yes.

>>> l = lambda *x: print(x) >>> l(1,2,3) (1, 2, 3) 

4 Comments

Note that this will only work with Python3. This syntax isn't supported in Python2.
More precisely, lambda *x: will work in Python 2, but print inside a lambda only works in Python 3.
Note that in print(x), it will print the arguments as a tuple, while print(*x) would call print with the arguments unpacked.
Thanks @Andreas Haferburg (@"Joe Koberg" thanks also but the "print(x) was a bit confusing, isn't it ?
0

Yes:

#lambda function with *args l1=[1,2,3,4] l2=(1,2,3,4) val=lambda *args : sum(args ) val(*l1,*l2) 

3 Comments

Please make the relevant difference to stackoverflow.com/a/2914938/7733418 more obvious. Explaining how your code works and why it helps would do that.
This answer was flagged as Low Quality, and could benefit from an explanation. Here are some guidelines for How do I write a good answer?. Code only answers are not considered good answers, and are likely to be downvoted and/or deleted because they are less useful to a community of learners. It's only obvious to you. Explain what it does, and how it's different / better than existing answers. From Review
This also essentially duplicates the other two answers.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.