List comprehension vs map

前端 未结 11 1796
长情又很酷
长情又很酷 2020-11-21 04:39

Is there a reason to prefer using map() over list comprehension or vice versa? Is either of them generally more efficient or considered generally more pythonic

相关标签:
11条回答
  • 2020-11-21 05:02

    Actually, map and list comprehensions behave quite differently in the Python 3 language. Take a look at the following Python 3 program:

    def square(x):
        return x*x
    squares = map(square, [1, 2, 3])
    print(list(squares))
    print(list(squares))
    

    You might expect it to print the line "[1, 4, 9]" twice, but instead it prints "[1, 4, 9]" followed by "[]". The first time you look at squares it seems to behave as a sequence of three elements, but the second time as an empty one.

    In the Python 2 language map returns a plain old list, just like list comprehensions do in both languages. The crux is that the return value of map in Python 3 (and imap in Python 2) is not a list - it's an iterator!

    The elements are consumed when you iterate over an iterator unlike when you iterate over a list. This is why squares looks empty in the last print(list(squares)) line.

    To summarize:

    • When dealing with iterators you have to remember that they are stateful and that they mutate as you traverse them.
    • Lists are more predictable since they only change when you explicitly mutate them; they are containers.
    • And a bonus: numbers, strings, and tuples are even more predictable since they cannot change at all; they are values.
    0 讨论(0)
  • 2020-11-21 05:09

    Here is one possible case:

    map(lambda op1,op2: op1*op2, list1, list2)
    

    versus:

    [op1*op2 for op1,op2 in zip(list1,list2)]
    

    I am guessing the zip() is an unfortunate and unnecessary overhead you need to indulge in if you insist on using list comprehensions instead of the map. Would be great if someone clarifies this whether affirmatively or negatively.

    0 讨论(0)
  • 2020-11-21 05:11

    I tried the code by @alex-martelli but found some discrepancies

    python -mtimeit -s "xs=range(123456)" "map(hex, xs)"
    1000000 loops, best of 5: 218 nsec per loop
    python -mtimeit -s "xs=range(123456)" "[hex(x) for x in xs]"
    10 loops, best of 5: 19.4 msec per loop
    

    map takes the same amount of time even for very large ranges while using list comprehension takes a lot of time as is evident from my code. So apart from being considered "unpythonic", I have not faced any performance issues relating to usage of map.

    0 讨论(0)
  • 2020-11-21 05:15

    Python 2: You should use map and filter instead of list comprehensions.

    An objective reason why you should prefer them even though they're not "Pythonic" is this:
    They require functions/lambdas as arguments, which introduce a new scope.

    I've gotten bitten by this more than once:

    for x, y in somePoints:
        # (several lines of code here)
        squared = [x ** 2 for x in numbers]
        # Oops, x was silently overwritten!
    

    but if instead I had said:

    for x, y in somePoints:
        # (several lines of code here)
        squared = map(lambda x: x ** 2, numbers)
    

    then everything would've been fine.

    You could say I was being silly for using the same variable name in the same scope.

    I wasn't. The code was fine originally -- the two xs weren't in the same scope.
    It was only after I moved the inner block to a different section of the code that the problem came up (read: problem during maintenance, not development), and I didn't expect it.

    Yes, if you never make this mistake then list comprehensions are more elegant.
    But from personal experience (and from seeing others make the same mistake) I've seen it happen enough times that I think it's not worth the pain you have to go through when these bugs creep into your code.

    Conclusion:

    Use map and filter. They prevent subtle hard-to-diagnose scope-related bugs.

    Side note:

    Don't forget to consider using imap and ifilter (in itertools) if they are appropriate for your situation!

    0 讨论(0)
  • 2020-11-21 05:17

    If you plan on writing any asynchronous, parallel, or distributed code, you will probably prefer map over a list comprehension -- as most asynchronous, parallel, or distributed packages provide a map function to overload python's map. Then by passing the appropriate map function to the rest of your code, you may not have to modify your original serial code to have it run in parallel (etc).

    0 讨论(0)
提交回复
热议问题