如何迭代切片?
Posted
技术标签:
【中文标题】如何迭代切片?【英文标题】:How to iterate over a slice? 【发布时间】:2019-07-23 07:09:07 【问题描述】:python 中的slice
是不可迭代的。这段代码:
s = slice(1, 10, 2)
iter(s)
导致此错误:
TypeError: 'slice' object is not iterable
这是我通过创建可迭代列表来显示切片的代码:
list(range(s.start, s.stop, s.step))
这使用切片对象的start
、stop
和step
属性。我将它们插入一个范围(不可变的序列类型)并创建一个列表:
[1, 3, 5, 7, 9]
有什么遗漏吗?我可以更好地迭代切片吗?
【问题讨论】:
你不应该只需要一个range(1, 10, 2)
吗?
范围或多或少与切片非常相似,因此我可以使用范围来生成该序列,但我专注于深入了解切片是什么以及如何操作它。切片不是先来的吗?那么范围呢? Range 似乎是一个生成器,内存效率更高。
此外,在实现__setitem__
时,原始问题具有实际相关性,您希望在其中支持切片。
range(s.start, s.stop, s.step)
在 s.start 或 s.step 为 None 时不起作用。
【参考方案1】:
slice
不是可迭代的。它不包含元素,而是指定如果切片应用于该可迭代对象,则返回其他可迭代对象中的哪些元素。
由于它不是可迭代的,因此您无法对其进行迭代。但是,正如您所发现的,您可以使用 range()
获取它将从应用它的可迭代对象中返回元素的索引 - 您可以对其进行迭代:
s = slice(1, 10, 2)
indices = range(s.start, s.stop, s.step)
it = iter(indices)
>>> list(it)
[1, 3, 5, 7, 9]
【讨论】:
我想到了将 slice() 子类化。 class Myslice(slice): 然后 def __getitem__(self,key) 但我不知道还要放什么。目前它超出了我的愚蠢程度。 你会发现这有点棘手……class X(slice): pass
的结果是TypeError: type 'slice' is not an acceptable base type
。
如果可能的话,您将定义一个返回 iter(range(self.start, self.stop, self.step))
的 __iter__
方法——但鉴于我之前的评论,这一点没有实际意义。
你说......'切片不是可迭代的。它不包含元素,......' 文档说......'......返回一个表示索引集的切片对象......',现在,'索引集' - 它们不是'元素'? “元素”有更具体的定义吗?
在这种情况下,“索引集”不是元素,不是。它们是“您将获得的元素所在的位置,无论您将此切片应用于什么”。另外,请注意使用的词是“代表”,而不是“包含”。将切片视为类似于函数签名可能会有所帮助。这不是一个东西,这是一个描述。【参考方案2】:
将切片转换为范围,然后可以迭代范围。
range(10**10)[slice]
【讨论】:
顺便提一下,为什么 range 需要 stop 参数?为什么不默认为无穷大?似乎range()
对于非负整数范围来说是一个很好的习惯用法。
当我这样做的时候,我刚刚拿回了切片 - 但做 list(range(1000))[slicer]
工作给了我价值。 (Python 3)。
list(range(1000)) 是次优的,因为它必须填满内存,如果你希望它有效地无限,这是一个问题。
“当我这样做时,我刚刚得到了切片”不,你得到了一个表现得像切片的范围。不同之处在于您可以迭代范围。您不能迭代切片。见原帖。 ```
嗯...你是对的。我一定是打错字什么的,因为我以为我做了同样的事情,type(foo)
是一个切片。这次是类型范围,并且没有列表就可以很好地迭代。呜呜呜。【参考方案3】:
问题比答案更笼统。 Slice 可以将浮点数作为一个步骤,其中 range 只能采用整数。所以更一般地说:
test=slice(0,1,0.01)
testlist=[x*test.step for x in range(0,int((test.stop-test.start)/test.step+1))]
您可能会遇到舍入错误,其中讨论了替代方案here
【讨论】:
以上是关于如何迭代切片?的主要内容,如果未能解决你的问题,请参考以下文章