Reputation: 113
I'm not sure why the code below works. According to docs, map only takes one function as the first argument and applies it to one or more iterables, depending on how many parameters the function takes.
map(function, iterable..)
However, in place of iterables, you can pass multiple functions and somehow they are treated as iterables. Somehow this line is taking the functions add, square and str and treating them as iterables.
How are functions being considered valid iterables?
def add(x):
return x + x
def square(x):
return x * x
nums = [1, 2, 3, 4, 5]
for i in nums:
vals = list(map(lambda x: x(i), (add, square, str)))
print(vals)
returns:
[2, 1, '1']
[4, 4, '2']
[6, 9, '3']
[8, 16, '4']
[10, 25, '5']
*EDIT
Martijn answered the question. This code does the same thing but breaks it out of the lambda function showing how add, square, str
are functions being iterated upon.
def add(x):
return x + x
def square(x):
return x * x
def act_on_iter(iter_obj, i):
return iter_obj(i)
nums = [1, 2, 3, 4, 5]
for i in nums:
vals = list(map(act_on_iter, (add, square, str), [i] * 3))
print(vals)
returns the same
[2, 1, '1']
[4, 4, '2']
[6, 9, '3']
[8, 16, '4']
[10, 25, '5']
Upvotes: 2
Views: 4119
Reputation: 1122222
You are passing in an iterable of callables:
(add, square, str)
That's a tuple, and tuples are iterables. It doesn't matter what's inside the iterable, and in Python, functions are first-class objects, just like strings and integers and classes and instances. You can pass functions around, including storing them in a tuple.
You then have a lambda
callable:
lambda x: x(i)
which takes each of the items in your iterable and treats those as callables too. x
is set to add
, then to square
, then to str
, and the lambda
calls each passing in i
. Again, functions are just another type of object, you can pass one function as an argument value to another, and here the parameter that received the function object is named x
. The expression x(i)
then calls whatever is assigned to x
.
If you replace the lambda
with print
(no ()
parentheses, we are referencing the function object), then you'd see:
>>> list(map(print, (add, square, str)))
<function add at 0x11645a670>
<function square at 0x11645a790>
<class 'str'>
[None, None, None]
The [None, None, None]
list is the result of calling print()
three times, that function always returns None
. The interesting part is the output before the [None, None, None]
, those are the string representations of each of the three functions in the (add, square, str)
tuple.
In your sample code, you have a for
loop over nums
, assinging each value to i
, so 1
, 2
, 3
, etc. So the actual output you see is produced by using map()
repeatedly, as i
changes:
i = 1
, -> [add(1), square(1), str(1)]
-> [2, 1, '1']
i = 2
, -> [add(2), square(2), str(2)]
-> [4, 4, '2']
i = 3
, -> [add(3), square(3), str(3)]
-> [6, 9, '3']
i = 4
, -> [add(4), square(4), str(4)]
-> [8, 16, '4']
i = 5
, -> [add(5), square(5), str(5)]
-> [10, 25, '5']
Upvotes: 6