I've been a procedural programmer for a while now, and just trying to switch my mindset to use functional programming (in Python 3 for now). So, instead of writing a for-each loop, I'm trying to grasp the interaction betweenmap
andlist(map(..))
Lets say I have a simplefor-in
loop which does some resource heavy computation (which I'll replace withprint
here for the sake of simplicity):
arr = [1,2,3,4] for x in arr: print(x)
Now, when I try to do the following
map(lambda x: print(x), arr)
nothing happens, UNTIL, i wrap this in a list and it does my super heavyprint
function:
list(map(lambda x: print(x), arr))
Why? What am I missing? I understand map returns an iterator which is supposed to save memory instead of just holding the entire list right away. But when is my super heavyprint
function going to be triggered then?
- Okay, I understand those concepts, they're not foreign to me. My question is, why doesn't the function work when I'm not applying the
list
wrapper? Because I have to trigger it through the iterator?Ognjen Mišić– Ognjen Mišić2018-02-26 22:10:52 +00:00CommentedFeb 26, 2018 at 22:10 - 2Yes @OgnjenMišić.
map
is what's commonly know as beinglazy. It won't do any work (i.e. call you function to compute any values) unless ithas to. You can force map to compute a single value usingnext
. When you cast themap
iterator to be alist
however, you'reforcingmap
to compute all of its values and thus call your function.Chris– Chris2018-02-26 22:13:28 +00:00CommentedFeb 26, 2018 at 22:13 - 2Because it does not return you a list of values. It returns the iterator itself. Then you call
next(some_iterator)
on it to consume the next value, one by one. Until all values are consumed. Applyinglist
to it will make it for all the values and returns you a list with all the iterator values. Or you can use a for loopprogmatico– progmatico2018-02-26 22:16:15 +00:00CommentedFeb 26, 2018 at 22:16 - Okay, tried it out, thanks guys, it's much more clear now. @ChristianDean post your response so I can accept :)Ognjen Mišić– Ognjen Mišić2018-02-26 22:17:00 +00:00CommentedFeb 26, 2018 at 22:17
- And to be frank, I was expecting it to work like the JS version of map, but then again now that one also makes sense.Ognjen Mišić– Ognjen Mišić2018-02-26 22:18:59 +00:00CommentedFeb 26, 2018 at 22:18
2 Answers2
Why? What am I missing? I understand map returns an iterator which is supposed to save memory instead of just holding the entire list right away. But when is my super heavy
Themap
function is what's commonly known in programmer terminology aslazy. It won't do any work unless ithas to. This is more broadly known as in functional programming aslazy evaluation. Rather than immediately compute any values, themap
function instead returns what's known as aniterator. By doing this, it's delegating the job of compute the values it was givenback to you.
A single value can be computed by the iterator usingnext
:
>>> arr = [1, 2, 3]>>> it = map(lambda x: print(x), arr)>>> next(it)1>>>
However, when you casted the map iterator to be a list, you were forcing map to computeall of its values and thus call your function:
>>> it = map(lambda x: print(x), arr)>>> list(it)1234[None, None, None, None]>>>
Comments
As you said, you have to switch your mindset to use functional programming. One of the key concepts of functional programming islazy evaluation, which is the default policy in languages such asHaskell.
The purpose of this policy is to save both time and memory, by calculating something only when it is needed. In that sense Pythongenerators are also close to the functional paradigm.
If you want to execute it as soon as possible, you shouldn't write it in a functional style and fix it withlist()
if you don't care about the results. Using a loop is totally ok.
4 Comments
map
and lazy evaluation nicely. +1for
loops, is it fine to just inline them withlist
wrapper and execute one list-map-lambda one after another or to still stick with nesting?for
loops rather than nestedmap
calls as it'd generally be faster. Also look intocomprehensions and see the question"OOP vs Functional Programming vs Procedural "map
+lambda
andfilter
+lambda
, note, list/generator/set/dict comprehensions are more efficient when you want to mapand filter at the same time. But in Python, you should only go with these constructs when readable, and don't use side-effects inside of them (... likeprint
...)Explore related questions
See similar questions with these tags.