3

The following code behaves differently in Python 2 vs Python 3:

all(map(lambda x,y: x, [1, 2], [1, 2, 3]))

Python 2 gives False whereas Python 3 gives True. The documentation for Python 2 says that it will supply None if the shorter list is exhausted but Python 3 doesn't do that.

I am working on a code that really needs the length to be maintained for some reason. What is the cleanest way to get the old behavior? I know I can use from past.builtin import map as old_map, but is there a more elegant solution that would work in both versions?

Nishant
  • 20,354
  • 18
  • 69
  • 101
  • can you rewrite the code? perhaps put that functionality in a function without using the differing constructs? – Joachim Lusiardi Mar 04 '20 at 18:57
  • Why don't you use your own custom function for this purpose? – mrzrm Mar 04 '20 at 18:59
  • 1
    @JoachimLusiardi It is a heavily used codey ... so I would like to minimize the changes. – Nishant Mar 04 '20 at 19:03
  • @mrzrm, Then I could just use `from past.builtin import map` :-) – Nishant Mar 04 '20 at 19:05
  • How many of the details of your example match what you're really doing? Because `len(list_1) >= len(list_2) and all(list_1)` seems like a much better way to solve the particular problem you show without messing around with backwards compatible versions of `map` or any alternative (like `itertools.zip_longest`). – Blckknght Mar 04 '20 at 19:11
  • @Blckknght I don't think I can change the solution. See this example: `all(map(compare_items, found, expected))`, it seems like the behaviour is really desired. – Nishant Mar 04 '20 at 19:15

1 Answers1

2

Essentially, map with multiple iterables for the arguments will zip the iterables, and then call the function with the tuples from the zip as var-args. So, you can get the same behaviour using itertools.starmap and zip:

>>> a = [10, 20]
>>> b = [1, 2, 3]
>>> f = lambda x, y: x
>>> list(map(f, a, b))
[10, 20]
>>> from itertools import starmap
>>> list(starmap(f, zip(a, b)))
[10, 20]

Then the behaviour you want can be achieved by replacing zip with itertools.zip_longest:

>>> from itertools import starmap, zip_longest
>>> list(starmap(f, zip_longest(a, b)))
[10, 20, None]

Both functions from itertools also exist in Python 2, except the second one is named izip_longest instead. You can just import ... as ... to get around that.

kaya3
  • 47,440
  • 4
  • 68
  • 97