Python 3 vs Python 2 map behavior

☆樱花仙子☆ 提交于 2019-11-27 01:50:08

问题


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...


回答1:


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




回答2:


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)]



回答3:


you can solve the problem like this: list(map(lambda x, y: (x, y),[1, 2, 3 ,4, 5], [6, 7, 8, 9, 10]))



来源:https://stackoverflow.com/questions/12015521/python-3-vs-python-2-map-behavior

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!