Python for 循环取模

Python for loop with modulo

是否可以使用模运算创建 python for 循环?我在 Python 中有一个环形缓冲区,我想迭代 startPosendPos 索引之间的元素,其中 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);
}

在 Python 中有没有办法轻松做到这一点?我只找到了

for i in list:
    print buffer[i]

语法但没有为我的问题提供等效的解决方案。

我的下一个方法是在迭代存储在列表中的索引之前预先创建列表。但是有没有办法像在其他编程语言中那样通过直接在 for 循环中使用模运算来像在其他编程语言中一样单行执行此操作?

使用范围

for i in range(0,len(a)):
      #code
      i=i%x

For 循环可以采用任何可迭代对象。因此,您可以创建自己的来完成工作并将其放入 for 循环中。例如:

for i in [i % ring_buffer for i in range(start_pos, end_pos)]:
    # Do stuff...

或者,直接创建一个可迭代对象:

for i in (i % ring_buffer for i in range(start_pos, end_pos)):
    # Do stuff...

请参阅 the docs 了解有关何时可能需要为此目的直接创建迭代器的详细信息。

你有一些方法可以做到这一点:

正如您在 "other programing languages" 中所做的那样(即 C 派生语法),只是您基本上必须以 while 形式编写它们的 for 循环 - 然后您意识到 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

现在,对于 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

请注意,虽然第二种形式是 "bigger",但它确实抽象了您的循环缓冲区逻辑,避免了硬代码值在您不需要查看它们的地方与它们的含义混淆 - 也就是说, 在 for 主体内部。

请注意 Python 中 for 的实际想法是遍历 缓冲区 内容本身,而不是指向其内容的索引.
因此,Python 标准库包含一个现成的循环缓冲区对象,它的索引始终规范化为 0 和 (len - 1) - 只需从 collections 模块导入 deque

如果你想要一个循环缓冲区,其开始和结束索引会改变,taht 将环绕并在 for 语句中自动工作,这也相对容易做到 - 如果你不需要完整的功能,只需子类化list,添加 startend 索引,并对其 __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)]

现在您可以在代码中使用这个自定义容器了:

In [22]: mylist = Circular(range(8), 6 , 2)

In [23]: for i in mylist:
    ...:     print(i)
    ...:     
6
7
0
1

我相信您应该能够使用 while 而不是 for 循环。只要您只想每次将 i 递增 1,然后计算 mod.

,这应该可以工作

尝试:

i = startPos
while (i <= endPos and i == (i+1) % ringBufferSize) :
    print buffer.getElementAt(x)
    i = i+1