为什么map与izip_longest一样有fill = None?

时间:2015-05-08 16:03:11

标签: python dictionary zip

map具有不同长度的输入时,填充值None将用于缺少的输入:

>>> x = [[1,2,3,4],[5,6]]
>>> map(lambda *x:x, *x)
[(1, 5), (2, 6), (3, None), (4, None)]

这与以下行为相同:

>>> import itertools
>>> list(itertools.izip_longest(*x))
[(1, 5), (2, 6), (3, None), (4, None)]

map提供此行为的原因是什么,而不是以下内容?

>>> map(lambda *x:x, *x)
[(1, 5), (2, 6), (3,), (4,)]

...是否有一种简单的方法可以使用zipmap的某种风格来获得后一种行为?

2 个答案:

答案 0 :(得分:5)

我认为这是核心开发人员在实施map时选择的设计决策。当map与多个可迭代项一起使用时,Map (higher-order function)引用时没有普遍定义的行为:

  

使用2个或更多列表的地图遇到处理时的问题   列表有不同的长度。各种语言不同;一些   引发异常,有些在最短列表的长度后停止   并忽略其他列表中的额外项目;一些继续到   最长列表的长度,以及已经结束的列表,   将一些占位符值传递给函数,表示没有值。

因此,Python核心开发人员选择None作为占位符,以便在1993年map was introduced向Python提供更短的迭代次数。

但是在itertools.imap的情况下,它以最短的可迭代次数进行短路,因为它的设计受到了标准ML,Haskell和APL等语言的极大启发。在标准ML和Haskell中map以最短的可迭代结束(虽然我不确定APL)。

Python 3还删除了map(None, ...)(或者我们应该说itertools.imap,Python 3' map实际上几乎是itertools.imapMove map() from itertools to builtins)构造因为它只存在于Python 2中,因为当时map被添加到Python中,Python中没有zip()函数。

来自Issue2186: map and filter shouldn't support None as first argument (in Py3k only)

  

我同意Guido的意见,如果我们永远不会创建map(None, ...)   zip()已经存在。主要用例已过时。

要获得您想要的结果,我建议您使用带有标记值(itertools.izip_longest)的object()而不是默认NoneNone如果迭代本身会破坏事物包含None

from itertools import izip_longest


def solve(seq):
    sentinel = object()
    return [tuple(x for x in item if x is not sentinel) for item in 
            izip_longest(*seq, fillvalue=sentinel)]


print solve([[1,2,3,4],[5,6]])
# [(1, 5), (2, 6), (3,), (4,)] 

答案 1 :(得分:1)

鉴于第一个列表总是更长,而且只有两个列表,你可以这样做:

x = [1,2,3,4,5]
y = ['a','b']
zip(x,y) + [(i,) for i in x[len(y):]]
[(1, 'a'), (2, 'b'), (3,), (4,), (5,)]