Python itertools和跨步列表分配
给定一个列表,例如Python itertools和跨步列表分配,python,slice,itertools,Python,Slice,Itertools,给定一个列表,例如x=[True]*20,我想将False分配给其他每个元素 x[::2] = False 引发TypeError:必须将iterable分配给扩展切片 所以我天真地认为你可以这样做: x[::2] = itertools.repeat(False) 或 然而,据我所知,这导致了一个无限循环。为什么会有一个无限循环?是否有一种替代方法不涉及在赋值之前知道切片中元素的数量 编辑:我知道x[::2]=[False]*len(x)/2在这种情况下起作用,或者在更一般的情况下,您可以
x=[True]*20
,我想将False
分配给其他每个元素
x[::2] = False
引发TypeError:必须将iterable分配给扩展切片
所以我天真地认为你可以这样做:
x[::2] = itertools.repeat(False)
或
然而,据我所知,这导致了一个无限循环。为什么会有一个无限循环?是否有一种替代方法不涉及在赋值之前知道切片中元素的数量
编辑:我知道
x[::2]=[False]*len(x)/2
在这种情况下起作用,或者在更一般的情况下,您可以在右侧找到一个乘法器表达式。我试图理解是什么导致itertools无限循环,以及为什么列表分配的行为不同于numpy数组分配。我认为python一定有一些基本的东西,我对此有所误解。我最初还认为,可能是出于性能原因,您更喜欢itertools而不是列表理解或创建另一个n元素列表。您在这段代码中试图做的事情与您的想法不同(我怀疑)
例如:x[::2]
将返回一个包含x的每个奇数
元素的切片,因为x的大小为20,切片的大小为10,但您正在尝试为其指定大小为1的不可替代项 要成功使用您拥有的代码,您需要执行以下操作:
x = [True]*20
x[::2] = [False]*10
wich会将大小为10的iterable分配给大小为10的切片
为什么要在黑暗中工作?使用
len(x[::2])
等于10,然后使用
x[::2] = [False]*len(x[::2])
您还可以执行以下操作:
x = [True if (index & 0x1 == 0) else False for index, element in enumerate(x)]
编辑:由于操作编辑 on循环表示它
无限重复。
这意味着它将通过给定的迭代器持续“循环”
Repeat有一个类似的实现,但是声明它无限期运行,除非指定了times参数。
问题代码中没有这样做。因此,两者都将导致无限循环 关于
itertools
更快的评论。是的,itertools通常比其他实现更快,因为它们经过优化,能够以创建者所能达到的速度运行
但是,如果不想重新创建列表,可以使用生成器表达式
,例如:
x = (True if (index & 0x1 == 0) else False for index, element in enumerate(x))
它们不会将所有元素都存储在内存中,而是在需要时生成它们,但是,生成器功能可能会耗尽
例如:
x = [True]*20
print(x)
y = (True if (index & 0x1 == 0) else False for index, element in enumerate(x))
print ([a for a in y])
print ([a for a in y])
将打印x
,然后是生成器中的元素y
,然后是空列表,因为生成器已用完。请尝试以下操作:
l = len(x)
x[::2] = itertools.repeat(False, l/2 if l % 2 == 0 else (l/2)+1)
您的原始解决方案以无限循环结束,因为这是repeat
应该做的,从以下方面:
制作一个迭代器,反复返回对象。除非指定了times参数,否则将无限期运行
切片
x[::2]
的长度正好是len(x)/2
元素,因此您可以通过以下方式实现所需:
x[::2] = [False]*(len(x)/2)
itertools.repeat
和itertools.cycle
方法旨在无限地产生值。但是,您可以在repeat()
上指定限制。像这样:
x[::2] = itertools.repeat(False, len(x)/2)
扩展切片赋值的右侧需要是大小合适的iterable(在本例中为10) 这是它的右边有一个常规列表:
>>> x = [True] * 20
>>> x[::2] = [False] * 10
>>> x
[False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True]
这是itertools。在右边重复
>>> from itertools import repeat
>>> x = [True] * 20
>>> x[::2] = repeat(False, 10)
>>> x
[False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True]
正如马克·托洛宁(Mark Tolonen)在一篇简洁的评论中指出的那样,itertools尝试无限期循环的原因是,对于列表赋值,python正在检查右侧的长度
>>> from itertools import repeat
>>> x = [True] * 20
>>> x[::2] = repeat(False, 10)
>>> x
[False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True]
现在要真正深入研究
当你说:
x[::2] = itertools.repeat(False)
左侧(x[::2]
)是一个列表,您正在为一个列表分配一个值,其中的值是itertools。重复(False)
iterable,它将永远迭代,因为它没有给定长度(根据)
如果您深入研究cPython实现中的列表分配代码,您将发现不幸/痛苦地命名的函数,它是许多列表分配内容的根源。在该代码中,您将看到:
这里,它试图获取分配给列表的iterable的长度(n
)。然而,甚至在到达那里之前,它就被卡住了,它最终尝试将您的iterable转换为一个列表(with),在其中它最终创建一个空列表,并尝试简单地用您的iterable扩展它
要使用iterable扩展列表,它使用,在这里您将看到问题的根源:
/* Run iterator to exhaustion. */
for (;;) {
就这样
或者至少我这么认为……:)这是一个有趣的问题,所以我想我会有一些乐趣,并通过挖掘源代码,看看发生了什么,并在那里结束
至于numpy数组的不同行为,这只是处理numpy.array
赋值方式的不同
请注意,使用itertools.repeat
在numpy中不起作用,但它不会挂断(我没有检查实现以找出原因):
这正是我想做的。我是从一个numpy用户的角度来看的。如果有
x=numpy.ones(10,dtype='bool')
,x[::2]=False
将数组的第0,2,4,6,8个元素设置为False。我想知道,即使使用itertools,为什么列表的等效项也会失败。numPy通常会以与普通python不同的方式处理事情,这是有充分理由的,但在这种情况下,x[::2]
返回一个大小为x/2
的列表,其中包含0,2,4,6,8…
th个元素。要以正常的python方式进行,请使用列表理解的flexability。为什么x[::2]无限地要求赋值?在我的原始示例中,只有10个元素需要赋值。为什么不对itertools调用设置限制?不,repeat
products
/* Run iterator to exhaustion. */
for (;;) {
>>> 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)