python map, list(map), lambda and performance

2019-06-09 17:19发布

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 between map and list(map(..))

Lets say I have a simple for-in loop which does some resource heavy computation (which I'll replace with print 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 heavy print 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 heavy print function going to be triggered then?

2条回答
淡お忘
2楼-- · 2019-06-09 17:35

As you said, you have to switch your mindset to use functional programming. One of the key concepts of functional programming is lazy evaluation, which is the default policy in languages such as Haskell.

The purpose of this policy is to save both time and memory, by calculating something only when it is needed. In that sense Python generators 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 with list() if you don't care about the results. Using a loop is totally ok.

查看更多
时光不老,我们不散
3楼-- · 2019-06-09 17:51

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 print function going to be triggered then?

The map function is what's commonly known in programmer terminology as lazy. It won't do any work unless it has to. This is more broadly known as in functional programming as lazy evaluation. Rather than immediately compute any values, the map function instead returns what's known as an iterator. By doing this, it's delegating the job of compute the values it was given back to you.

A single value can be computed by the iterator using next:

>>> 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 compute all of its values and thus call your function:

>>> it = map(lambda x: print(x), arr)
>>> list(it)
1
2
3
4
[None, None, None, None]
>>> 
查看更多
登录 后发表回答