python – itertools和strided list assignment

给出一个列表,例如x = [True] * 20,我想为每个其他元素指定False.

x[::2] = False

引发TypeError:必须将iterable分配给扩展切片

所以我天真地认为你可以这样做:

x[::2] = itertools.repeat(False)

要么

x[::2] = itertools.cycle([False])

但是,据我所知,这导致无限循环.为什么会出现无限循环?是否有一种替代方法不涉及在分配之前知道切片中元素的数量?

编辑:我理解x [:: 2] = [False] * len(x)/ 2在这种情况下有效,或者你可以在更一般的情况下为右侧的乘数提出一个表达式.我试图理解是什么导致itertools无限循环,以及为什么列表赋值的行为与numpy数组赋值不同.我认为python必须有一些基本的东西,我误解了.我原本也在考虑可能有性能原因偏好itertools列出理解或创建另一个n元素列表.

解决方法:

正如Mark Tolonen在一篇简明的评论中指出的那样,你的itertools尝试无限循环的原因是因为,对于列表赋值,python正在检查右侧的长度.

现在要真正挖掘……

当你说:

x[::2] = itertools.repeat(False)

左侧(x [:: 2])是一个列表,您要为列表赋值,其中值为itertools.repeat(False)iterable,它将永远迭代,因为它没有给出长度(按照the docs).

如果你深入研究cPython实现中的列表赋值代码,你会发现不幸/痛苦命名的函数list_ass_slice,它是许多列表赋值的根源.在该代码中,您将看到this segment

v_as_SF = PySequence_Fast(v, "can only assign an iterable");
if(v_as_SF == NULL)
    goto Error;
n = PySequence_Fast_GET_SIZE(v_as_SF);

这里它试图获得您分配给列表的可迭代的长度(n).然而,在它到达那里之前它会在PySequence_Fast停留,它最终试图将你的iterable转换为一个列表(使用PySequence_List),在其中它最终创建一个空列表并尝试用你的iterable简单地扩展它.

要使用iterable扩展列表,它使用listextend(),在那里你会看到问题的根源:

/* Run iterator to exhaustion. */
for (;;) {

然后你去

或者至少我是这么认为的…… :)这是一个有趣的问题,所以我想我会有一些乐趣,并通过源头挖掘看到了什么,并最终在那里.

至于numpy数组的不同行为,它将简单地处理numpy.array赋值的方式.

请注意,使用itertools.repeat在numpy中不起作用,但它不会挂起(我没有检查实现以找出原因):

>>> import numpy, itertools
>>> x = numpy.ones(10,dtype='bool')
>>> x[::2] = itertools.repeat(False)
>>> x
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)
>>> #but the scalar assignment does work as advertised...
>>> x = numpy.ones(10,dtype='bool')
>>> x[::2] = False
>>> x
array([False,  True, False,  True, False,  True, False,  True, False,  True], dtype=bool)
上一篇:python – itertools.product – 返回列表而不是元组


下一篇:在Python中生成置换词列表的子集