Dru*_*dge 3 python for-loop modulo
是否可以使用模运算创建python for循环?我在 Python 中有一个环形缓冲区,我想迭代startPos和endPos索引之间的元素,其中的startPos值可以大于endPos. 在其他编程语言中,我会用模运算符直观地实现这一点:
int startPos = 6;
int endPos = 2;
int ringBufferSize = 8;
for(int i = startPos, i != endPos, i = (i+1) % ringBufferSize) {
print buffer.getElementAt(i);
}
Run Code Online (Sandbox Code Playgroud)
有没有办法在 Python 中轻松做到这一点?我只找到了
for i in list:
print buffer[i]
Run Code Online (Sandbox Code Playgroud)
语法但没有为我的问题提供等效解决方案。
我的下一个方法是在迭代存储在列表中的索引之前提前创建列表。但是有没有办法像在其他编程语言中一样通过直接在 for 循环中使用模运算来做到这一点?
你有一些方法可以做到这一点:
正如您在“其他编程语言”(即 C 派生语法)中所做的那样,您基本上必须以forwhile 形式编写它们的循环 - 然后您意识到 C 的 for 只是一个while:
start_pos = 6
end_pos = 2
ring_buffer_size = 8
i = start_pos
while True:
i = (i + 1) % ring_buffer_size
if i <= end_pos:
break
# your code here
Run Code Online (Sandbox Code Playgroud)
现在,对于 for语句,Python 只有所谓的“for each”——它总是遍历一个迭代或序列。所以你可以创建一个迭代来产生你的价值 -
def ring(start, end, buffer_size, increment=1):
i = start
while i != end:
yield i
i += 1
i %= buffer_size
for slot in ring(6, 2, 8):
# your code here
Run Code Online (Sandbox Code Playgroud)
请注意,虽然第二种形式“更大”,但它确实抽象了您的循环缓冲区逻辑,避免了硬代码值与其含义混合在一起,而您无需查看它们 - 即在for主体内部。
请注意,for在 Python中的实际想法是迭代缓冲区内容本身,而不是将导致其内容的索引。
因此,Python 标准库已经包含一个现成的循环缓冲区对象,该对象的索引始终标准化为 0 和 (len - 1) - 只需deque从collections模块导入。
如果您想要一个具有更改开始和结束索引的循环缓冲区,它将环绕并自动在for语句中工作,这也相对容易 - 如果您不需要完整功能,只需子类化 list,添加start和end索引,并进行自定义其__iter__方法的实现:
class Circular(list):
def __init__(self, content, start, end):
super(Circular, self).__init__( content)
self.start = start
self.end = end
def __iter__(self):
for i in range(self.start, self.start + len(self)):
if i % len(self) == self.end: break
yield self[i % len(self)]
Run Code Online (Sandbox Code Playgroud)
现在您可以在代码中使用这个自定义容器:
In [22]: mylist = Circular(range(8), 6 , 2)
In [23]: for i in mylist:
...: print(i)
...:
6
7
0
1
Run Code Online (Sandbox Code Playgroud)