0

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?

askedFeb 26, 2018 at 22:05
Ognjen Mišić's user avatar
5
  • 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 thelist wrapper? Because I have to trigger it through the iterator?CommentedFeb 26, 2018 at 22:10
  • 2
    Yes @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.CommentedFeb 26, 2018 at 22:13
  • 2
    Because it does not return you a list of values. It returns the iterator itself. Then you callnext(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 loopCommentedFeb 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 :)CommentedFeb 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.CommentedFeb 26, 2018 at 22:18

2 Answers2

6

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?

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]>>>
answeredFeb 26, 2018 at 22:24
Chris's user avatar
Sign up to request clarification or add additional context in comments.

Comments

3

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.

answeredFeb 26, 2018 at 22:24
nyr1o's user avatar

4 Comments

Nice answer Louis! This sums up the idea and purpose behindmap and lazy evaluation nicely. +1
Thanks for the response. I know that using a loop is fine, but then when does one write functional and when procedural? Lets say I have some nestedfor 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?
It real depends @OgnjenMišić. There both valid programming paradigms that each have pros and cons. In the case of your specific example, I'd opt to use nestedfor loops rather than nestedmap calls as it'd generally be faster. Also look intocomprehensions and see the question"OOP vs Functional Programming vs Procedural "
@OgnjenMišić in general, list-comprehensions are preferred overmap +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...)

Your Answer

Sign up orlog in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to ourterms of service and acknowledge you have read ourprivacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.