在Python 2中,一个常见的(旧的,遗留的)习惯是使用map
使用map(None,iter,iter,...)
形式连接不均匀长度的迭代器,如下所示:
>>> map(None,xrange(5),xrange(10,12))
[(0, 10), (1, 11), (2, None), (3, None), (4, None)]
在Python 2中,它被扩展,以便最长的迭代器是返回列表的长度,如果一个比另一个短,则用None
填充。
在Python 3中,这是不同的。首先,您不能将None
用作位置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
好的 - 我可以解决这个问题:
>>> def f(*x): return x
...
>>> list(map(f, *(range(5),range(10,12))))
[(0, 10), (1, 11)]
但现在,我遇到了另一个问题:map
返回最短迭代器的长度 - 不再填充None
。
当我将Python 2代码移植到Python 3时,这不是一个非常罕见的习惯用法,我还没有找到一个简单易用的解决方案。
不幸的是,2to3工具does not选择了这个 - 无益建议:
-map(None,xrange(5),xrange(10,18))
+list(map(None,list(range(5)),list(range(10,18))))
建议?
修改的
有一些讨论这个成语有多常见。 See this SO post。
当我还在高中时,我正在更新编写的遗留代码。看看Raymond Hettinger撰写的2003 Python教程written and discussed,指出了这个特定的地图行为。
答案 0 :(得分:18)
itertools.zip_longest
以更易于理解的名义做你想做的事。 :)
答案 1 :(得分:2)
这次我会回答我自己的问题。
使用Python 3x,您可以使用itertools.zip_longest,如下所示:
>>> 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)]
你也可以自己滚动我想:
>>> 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)]
答案 2 :(得分:0)
如果需要Python 2中一些过时的功能,则一种方法是-自己编写。当然,它不是内置功能,但至少是某些东西。
下面的代码段需要27行
#!/usr/bin/env python3
def fetch(sequence, index):
return None if len(sequence) <= index else sequence[index]
def mymap(f, *args):
max_len = 0
for i in range(len(args)):
max_len = max(max_len, len(args[i]))
out = []
for i in range(max_len):
t = []
for j in range(len(args)):
t.append(fetch(args[j],i))
if f != None:
# Use * for unpack arguments from Arbitarily argument list
# Use ** for unpack arguments from Keyword argument list
out.append(f(*t))
else:
out.append(tuple(t))
return out
if __name__ == '__main__':
print(mymap(None, [1,2,3,4,5],[2,1,3,4],[3,4]))
print(mymap(None,range(5),range(10,12)))