简体   繁体   English

Python中的无限循环-列表是否已更新?

[英]Infinite for loop in Python - is the list updated or not?

First of all, I am aware that I should use while loop to create an infinite one. 首先,我知道我应该使用while循环来创建一个无限循环。 Nevertheless, while playing with making an infinite for loop in Python I run into something I do not fully understand. 然而,尽管有做无限打for Python中环我碰到一些我不完全理解。

My idea for an "infinite" for loop was following: 我对“无限” for循环的想法如下:

l = [1]
for el in l:
  print(len(l))
  l.append(1)

and this in fact created an infinite loop as 1 was constantly appended to the list l at each loop iteration. 实际上,这会创建一个无限循环,因为在每次循环迭代时,都会将1不断添加到列表l中。 So I thought I do not want my list to become longer and longer so that at some point I have not enough memory. 因此,我认为我不希望列表越来越长,以至于在某个时候我没有足够的内存。 So I did this: 所以我这样做:

l = [1]
for el in l:
  print(len(l))
  l.pop(0)
  l.append(1)

and I got just one iteration. 而我只有一次迭代。 Can someone explain why? 有人可以解释为什么吗? Is it because the l is still referenced to the same object and its length is always 1? 是因为l仍然引用同一对象,并且其长度始终为1?

If you use an iterator as suggested above, it makes it way easier to implemented. 如果按照上面的建议使用迭代器 ,则可以更轻松地实现。
The class below implements the ___iter___ and ___next___ method needed for a iterator classes 下面的类实现了迭代器类所需的___iter______next___方法

class WhileLoop:

    def __init__(self, value):
        #Assign the value
        self.value = value

    def __iter__(self):
        #The iterator will be the class itself
        return self

    def __next__(self):
        #The next element in the loop is the value itself
        return self.value

You can then call and loop on this iterator as follows. 然后,您可以在此迭代器上调用并循环,如下所示。

loop = WhileLoop(1)
for item in loop:
    print(item)

The for statement returns an "iterator" which is a container for a stream of data that returns one element at a time, so you are not iterating over the iterable (your list in this case) but instead over this container. for语句返回一个“迭代器”,该容器是用于一次返回一个元素的数据流的容器,因此您不是在可迭代对象(在这种情况下为列表)上进行迭代,而是在此容器上进行迭代。

You can return this iterator directly using iter() in order to better understand what is happening with your for loop. 您可以直接使用iter()返回此迭代器,以便更好地了解for循环的情况。

items = ['a']

it = iter(items)
print(it.__reduce__())
# (<built-in function iter>, (['a'],), 0)

The built in __reduce__() function returns state information about the iterator. 内置的__reduce__()函数返回有关迭代器的状态信息。 Note that the state information returned immediately after the iterator is created includes the iterable, ['a'] , and an index value of 0 . 请注意,在创建迭代器之后立即返回的状态信息包括可迭代的['a']和索引值0 The index value indicates the position of the next element that will be returned by the iterator. 索引值指示迭代器将返回的下一个元素的位置。

To simulate the first iteration of the loop, we can use next() which returns the next element from an iterator. 为了模拟循环的第一次迭代,我们可以使用next() ,它从迭代器返回下一个元素。

next(it)
print(it.__reduce__())
# (<built-in function iter>, (['a'],), 1)

Now we see that the index value has changed to 1 because the iterator already returned the first element in the list and on the next iteration it will attempt to return the second element in the list. 现在我们看到索引值已更改为1因为迭代器已经返回了列表中的第一个元素,并且在下一次迭代时它将尝试返回列表中的第二个元素。 If you attempt to remove the first element in the list and then append another element to the list, following is the resulting state of the iterator. 如果尝试删除列表中的第一个元素,然后将另一个元素追加到列表中,则下面是迭代器的结果状态。

items.pop(0)
items.append('b')
print(it.__reduce__())
# (<built-in function iter>, (['b'],), 1)

You can see that the first element was removed and the new element was appended (as expected). 您可以看到第一个元素已删除,新元素已附加(如预期的那样)。 However, the iterator still retained an index value of 1 as the position of the next element to be returned from iteration. 但是,迭代器仍保留索引值1作为要从迭代返回的下一个元素的位置。 If we attempt another iteration, a StopIteration exception will be raised because there is no element at index 1 in the iterable being used by our iterator container. 如果我们尝试另一次迭代,则会引发StopIteration异常,因为迭代器容器正在使用的可迭代对象的索引1处没有任何元素。

next(it)
# Traceback (most recent call last):
#   File "main.py", line 16, in <module>
#     next(it)
# StopIteration

If you are really interested in creating an infinite for loop, using a generator would be a better way to deal with your memory concerns (although as you note in your question, there aren't too many good reasons not to use while for this sort of thing). 如果你是在创造循环无限真正感兴趣的,使用一台发电机会是一个更好的方式来处理你的记忆担忧(尽管你在你的问题指出,没有太多的理由不使用while对于这种的东西)。 See my answer to a related question for an example of an infinite for loop . 有关无限for循环的示例,请参见我对相关问题的回答

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM