In Python 2 this code is OK:
f = lambda (m, k): m + k
m = [1,2,3,4]
k = [5,6,7,8]
print(map(f, zip(m, k)))
but in Python 3 the following error occurred:
f = lambda (m, k): m + k
^
SyntaxError: invalid syntax
If I remove parentheses in lambda expression then another error occurred:
TypeError: <lambda>() missing 1 required positional argument: 'k'
Also approach with tuple as single lambda argument works in Python 3, but it's not clear (hard for reading):
f = lambda args: args[0] + args[1]
How can I unpack values in the right way in Python 3?
The removal of tuple unpacking is discussed in PEP 3113. Basically, you can't do this in Python 3. Under the headline Transition plan, you see that the "suggested" way of doing this is as your final code block:
lambda x_y: x_y[0] + x_y[1]
You can use the same syntax in both Python 2 and Python 3 if you use itertools.starmap instead of map which unpacks the tuple items for us:
>>> from itertools import starmap
>>> f = lambda m, k: m + k
>>> list(starmap(f, zip(m, k)))
[6, 8, 10, 12]
You may find this solution easier to read:
lambda mk: (lambda m,k: m + k)(*mk)
Additionally, I'd argue that the unpacking makes this more (1) Pythonic and (2) consistent with the manual unpacking of tuple arguments for named functions, required in Python 3 by PEP 3113.
You cannot use parentheses in Python3 to unpack arguments in lambda functions (PEP 3113), Try:
f = lambda m, k: m + k
To make it work with your code, you should use:
lambda mk: mk[0] + mk[1]
Or you can just sum() to add numbers without unpack:
f = lambda args: sum(args)
Just use
map(f, m, k)
Note that f can be
from operator import add
map(add, m, k)
Related
Suppose I have a function like:
def myfun(a, b, c):
return (a * 2, b + c, c + b)
Given a tuple some_tuple = (1, "foo", "bar"), how can I use some_tuple to call myfun, to get the result (2, "foobar", "barfoo")
I know could define myfun so that it accepts the tuple directly, but I want to call the existing myfun.
See also: What do the * (star) and ** (double star) operators mean in a function call?.
myfun(*some_tuple) does exactly what you request. The * operator simply unpacks the tuple (or any iterable) and passes them as the positional arguments to the function. Read more about unpacking arguments.
Note that you can also expand part of argument list:
myfun(1, *("foo", "bar"))
Take a look at the Python tutorial section 4.7.3 and 4.7.4.
It talks about passing tuples as arguments.
I would also consider using named parameters (and passing a dictionary) instead of using a tuple and passing a sequence. I find the use of positional arguments to be a bad practice when the positions are not intuitive or there are multiple parameters.
This is the functional programming method. It lifts the tuple expansion feature out of syntax sugar:
apply_tuple = lambda f, t: f(*t)
Redefine apply_tuple via curry to save a lot of partial calls in the long run:
from toolz import curry
apply_tuple = curry(apply_tuple)
Example usage:
from operator import add, eq
from toolz import thread_last
thread_last(
[(1,2), (3,4)],
(map, apply_tuple(add)),
list,
(eq, [3, 7])
)
# Prints 'True'
Similar to #Dominykas's answer, this is a decorator that converts multiargument-accepting functions into tuple-accepting functions:
apply_tuple = lambda f: lambda args: f(*args)
Example 1:
def add(a, b):
return a + b
three = apply_tuple(add)((1, 2))
Example 2:
#apply_tuple
def add(a, b):
return a + b
three = add((1, 2))
Currently, this is how I resolve a "and" function using lambda with two arguments:
custom_function = lambda a, b: a and b
But how can I resolve an unknown number of arguments, like:
custom_function = lambda a, b, c, d, ...: what now?
Anybody had this issue before?
Thanks and Greetings!
You can use "*args":
>>> custom_function = lambda *args: all(args)
>>> custom_function(1, 2, 3)
True
>>> custom_function(1, 2, 3, 0)
False
Which indeed is the same as just using "all":
>>> all(1, 2, 3)
True
>>> all(1, 2, 3, 0)
False
To be general, you can use "functools.reduce" to use any "2-parameters" function with any number of parameters (if their order doesn't matter):
import operator
import functools
c = lambda *args: functools.reduce(operator.and_, args)
(same results as before)
You can use argument unpacking via the * operator to process any number of arguments. You would have to resort to reduce (Python2) or functools.reduce (Python3) in order to combine them all with and in a single expression (as needed by the lambda):
from functools import reduce # only Py3
custom_function = lambda *args: reduce(lambda x, y: x and y, args, True)
Note: this is not the same as all, like many here suggest:
>>> all([1,2,3])
True
>>> 1 and 2 and 3
3
>>> custom_function(1,2,3)
3
First, use *args to store an unknown number of arguments as a tuple.
Second, all(args) only return Ture or False but and operation may return value (Here is why). So we need to use reduce.
Here is the solution:
custom_function = lambda *args: reduce(lambda x,y: x and y, args)
Test 1: arguments are Ture or False
>>> custom_function(True,False,True,False)
False
>>> custom_function(True,True,True)
True
Test 2: arguments are values
>>> custom_function(1,2,3,4,3,2)
2
>>> custom_function('a','b','d','s')
's'
Test 3: arguments are a combination of bool and values
>>> custom_function(1,2,True,4,3,2)
2
>>> custom_function(1,2,False,4,3,2)
False
Note the three tests are correct according to the definition of Logical AND (and):
Return the first Falsey value if there are any, else return the last
value in the expression.
Why not just using the all function?
a = 1
b = 2
c = None
args = [a, b, c]
print (all(args))
# False
I am new to Python and practicing basics. I am using a lambda expression to take two arguments and performing square operations on them (eg: var ** 2). The two arguments are coming from the zip(list1, list2). I am getting TypeError for this. I tried searching for the solution but didn't get any. I even tried writing lambda arguments in parenthesis (eg: lambda (v1,v2):) but that threw SyntaxError.
Below is the python code:
list1 = [1,2,3,4]
list2 = [5,6,7,8]
print ( list(map(lambda v1,v2: (v1**2, v2**2), list(zip(list1, list2)))) )
Error:
TypeError Traceback (most recent call last)
<ipython-input-241-e93d37efc752> in <module>()
1 list1 = [1,2,3,4]
2 list2 = [5,6,7,8]
----> 3 print ( list(map(lambda v1,v2: (v1**2, v2**2), list(zip(list1, list2)))) )
TypeError: <lambda>() missing 1 required positional argument: 'v2'
You're giving a single list as argument to map, thus map calls your lambda with one element of the list at a time - that is one argument, even though it is a tuple. What you probably want is:
print ( list(map(lambda v: (v[0]**2, v[1]**2), zip(list1, list2))) )
so that your item from the list is passed as a sole argument to lambda.
If you insist on the two-argument lambda, discard zip and pass your lists directly to map as separate arguments:
print ( list(map(lambda v1,v2: (v1**2, v2**2), list1, list2)) )
In your print, map will cal the function lambda on a list of tuples (as list(zip(list1, list2)) produce a list of tuples).
So for instance you can do :
print(list(map(lambda(v1,v2): (v1**2, v2**2), list(zip(list1, list2)))))
Your lambda function will use the tuple (v1,v2) as parameters, instead of two parameters.
In Python 2 this code is OK:
f = lambda (m, k): m + k
m = [1,2,3,4]
k = [5,6,7,8]
print(map(f, zip(m, k)))
but in Python 3 the following error occurred:
f = lambda (m, k): m + k
^
SyntaxError: invalid syntax
If I remove parentheses in lambda expression then another error occurred:
TypeError: <lambda>() missing 1 required positional argument: 'k'
Also approach with tuple as single lambda argument works in Python 3, but it's not clear (hard for reading):
f = lambda args: args[0] + args[1]
How can I unpack values in the right way in Python 3?
The removal of tuple unpacking is discussed in PEP 3113. Basically, you can't do this in Python 3. Under the headline Transition plan, you see that the "suggested" way of doing this is as your final code block:
lambda x_y: x_y[0] + x_y[1]
You can use the same syntax in both Python 2 and Python 3 if you use itertools.starmap instead of map which unpacks the tuple items for us:
>>> from itertools import starmap
>>> f = lambda m, k: m + k
>>> list(starmap(f, zip(m, k)))
[6, 8, 10, 12]
You may find this solution easier to read:
lambda mk: (lambda m,k: m + k)(*mk)
Additionally, I'd argue that the unpacking makes this more (1) Pythonic and (2) consistent with the manual unpacking of tuple arguments for named functions, required in Python 3 by PEP 3113.
You cannot use parentheses in Python3 to unpack arguments in lambda functions (PEP 3113), Try:
f = lambda m, k: m + k
To make it work with your code, you should use:
lambda mk: mk[0] + mk[1]
Or you can just sum() to add numbers without unpack:
f = lambda args: sum(args)
Just use
map(f, m, k)
Note that f can be
from operator import add
map(add, m, k)
Suppose I have a function like:
def myfun(a, b, c):
return (a * 2, b + c, c + b)
Given a tuple some_tuple = (1, "foo", "bar"), how can I use some_tuple to call myfun, to get the result (2, "foobar", "barfoo")
I know could define myfun so that it accepts the tuple directly, but I want to call the existing myfun.
See also: What do the * (star) and ** (double star) operators mean in a function call?.
myfun(*some_tuple) does exactly what you request. The * operator simply unpacks the tuple (or any iterable) and passes them as the positional arguments to the function. Read more about unpacking arguments.
Note that you can also expand part of argument list:
myfun(1, *("foo", "bar"))
Take a look at the Python tutorial section 4.7.3 and 4.7.4.
It talks about passing tuples as arguments.
I would also consider using named parameters (and passing a dictionary) instead of using a tuple and passing a sequence. I find the use of positional arguments to be a bad practice when the positions are not intuitive or there are multiple parameters.
This is the functional programming method. It lifts the tuple expansion feature out of syntax sugar:
apply_tuple = lambda f, t: f(*t)
Redefine apply_tuple via curry to save a lot of partial calls in the long run:
from toolz import curry
apply_tuple = curry(apply_tuple)
Example usage:
from operator import add, eq
from toolz import thread_last
thread_last(
[(1,2), (3,4)],
(map, apply_tuple(add)),
list,
(eq, [3, 7])
)
# Prints 'True'
Similar to #Dominykas's answer, this is a decorator that converts multiargument-accepting functions into tuple-accepting functions:
apply_tuple = lambda f: lambda args: f(*args)
Example 1:
def add(a, b):
return a + b
three = apply_tuple(add)((1, 2))
Example 2:
#apply_tuple
def add(a, b):
return a + b
three = add((1, 2))