Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 vs Python 2 map behavior

Tags:

In Python 2, a common (old, legacy) idiom is to use map to join iterators of uneven length using the form map(None,iter,iter,...) like so:

>>> map(None,xrange(5),xrange(10,12))
[(0, 10), (1, 11), (2, None), (3, None), (4, None)]

In Python 2, it is extended so that the longest iterator is the length of the returned list and if one is shorter than the other it is padded with None.

In Python 3, this is different. First, you cannot use None as an argument for the callable in position 1:

>>> list(map(None, range(5),range(10,12)))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

OK -- I can fix that like so:

>>> def f(*x): return x    
... 
>>> list(map(f, *(range(5),range(10,12))))
[(0, 10), (1, 11)]

But now, I have a different problem: map returns the shortest iterator's length -- no longer padded with None.

As I port Python 2 code to Python 3, this is not a terrible rare idiom and I have not figured out an easy in place solution.

Unfortunately, the 2to3 tools does not pick this up -- unhelpfully suggesting:

-map(None,xrange(5),xrange(10,18))
+list(map(None,list(range(5)),list(range(10,18)))) 

Suggestions?


Edit

There is some discussion of how common this idiom is. See this SO post.

I am updating legacy code written when I was still in high school. Look at the 2003 Python tutorials being written and discussed by Raymond Hettinger with this specific behavior of map being pointed out...

like image 370
the wolf Avatar asked Aug 18 '12 03:08

the wolf


People also ask

Is there a big difference between Python 2 and 3?

Python 3 is definitely more readable, easier to grasp, and popular than Python 2. Python 2 has definitely run out of steam and one should learn Python 2 if and only if some legacy code has been written in Python 2 or if a company needs the developer to migrate the Python 2 code into Python 3.

What is difference between Python 2 and Python 3?

Python 3 is more in-demand and includes a typing system. Python 2 is outdated and uses an older syntax for the print function. While Python 2 is still in use for configuration management in DevOps, Python 3 is the current standard. Python (the code, not the snake) is a popular coding language to learn for beginners.

How do you tell if a script is Python 2 or 3?

If you want to determine whether Python2 or Python3 is running, you can check the major version with this sys. version_info. major . 2 means Python2, and 3 means Python3.

Which is faster Python 2 or 3?

Python 3.3 comes faster than Python 2.7.


2 Answers

itertools.zip_longest does what you want, with a more comprehensible name. :)

like image 144
Danica Avatar answered Oct 03 '22 00:10

Danica


I'll answer my own question this time.

With Python 3x, you can use itertools.zip_longest like so:

>>> list(map(lambda *a: a,*zip(*itertools.zip_longest(range(5),range(10,17)))))
[(0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (None, 15), (None, 16)]

You can also roll ur own I suppose:

>>> def oldMapNone(*ells):
...     '''replace for map(None, ....), invalid in 3.0 :-( '''
...     lgst = max([len(e) for e in ells])
...     return list(zip(* [list(e) + [None] * (lgst - len(e)) for e in ells]))
... 
>>> oldMapNone(range(5),range(10,12),range(30,38))
[(0, 10, 30), (1, 11, 31), (2, None, 32), (3, None, 33), (4, None, 34), (None, None, 35), (None, None, 36), (None, None, 37)]
like image 26
the wolf Avatar answered Oct 02 '22 23:10

the wolf