一个简单的Python迭代器进入无限循环

时间:2017-03-26 16:59:32

标签: python iterator generator yield

我试图编写一个我自己的简单倒计时迭代器,我实现了一个__iter__()函数和相应的__next__()来支持迭代器。我在里面使用了yield函数__next__()函数每次迭代对象时返回一个新值。 当我使用yield时,与使用return语句相比,代码在无限循环中进行。 以下是我的代码:

class MyIterator():
    def __init__(self,value):
        self.value = value
    def __iter__(self):
        return self
    def __next__(self):
        print("In the next function")
        if self.value > 0:
            yield self.value
            self.value -= 1
        else:
            raise StopIteration("Failed to proceed to the next step")



if __name__ == '__main__':
    myIt = MyIterator(10)
    for i in myIt:
        print(i)

O / P如下:

  <generator object __next__ at 0x101181990>
  <generator object __next__ at 0x1011818e0>
  <generator object __next__ at 0x101181990>
  <generator object __next__ at 0x1011818e0>

  and so on for infinite times....

2 个答案:

答案 0 :(得分:2)

您的__next__方法本身应该是生成器。将yield替换为return

def __next__(self):
    print("In the next function")
    if self.value > 0:
        return_value = self.value
        self.value -= 1
        return return_value
    else:
        raise StopIteration("Failed to proceed to the next step")

请注意,在确定要返回的内容后,您仍需要减少self.value,因此请使用单独的return_value变量。

任何带有yield的函数(或方法)在调用时都会生成一个生成器对象,然后该生成器就是可迭代的。然后,这样的对象具有__iter__方法,该方法返回self__next__方法,该方法在调用时将生成下一个值。这就是为什么每次调用<generator object __next__ at 0x1011818e0>时都会看到正在打印的__next__对象。

但是,为了使您的对象成为可迭代的,您的__next__方法应该返回序列中的下一个值。它会被重复调用,直到它引发StopIteration。这与使用yield不同,它应该立即返回,而不是推迟到以后!

演示:

>>> class MyIterator():
...     def __init__(self,value):
...         self.value = value
...     def __iter__(self):
...         return self
...     def __next__(self):
...         print("In the next function")
...         if self.value > 0:
...             return_value = self.value
...             self.value -= 1
...             return return_value
...         else:
...             raise StopIteration("Failed to proceed to the next step")
...
>>> myIt = MyIterator(10)
>>> for i in myIt:
...     print(i)
...
In the next function
10
In the next function
9
In the next function
8
In the next function
7
In the next function
6
In the next function
5
In the next function
4
In the next function
3
In the next function
2
In the next function
1
In the next function

如果你想使用生成器函数,请使__iter__生成器,并使用循环:

class MyIterator():
    def __init__(self,value):
        self.value = value
    def __iter__(self):
        value = self.value
        while value > 0:
            yield value
            value -= 1

但是,这会使您的MyIterator类成为可迭代的,而不是迭代器。相反,每次使用for循环时,都会创建 new 迭代器(__iter__生成器对象),然后迭代。使用__next__使您的对象成为只能在上迭代的迭代器。

答案 1 :(得分:2)

这里有点混乱。当您使用 yield 时,您不需要创建迭代器类。生成器已经是迭代器。

所以,将 yield 更改为 return ,它会做你想做的事: - )

此外,您需要在 self.value之前更新return 。这是固定代码的样子:

class MyIterator():
    def __init__(self,value):
        self.value = value
    def __iter__(self):
        return self
    def __next__(self):
        print("In the next function")
        value = self.value
        if value > 0:
            self.value -= 1
            return value
        else:
            raise StopIteration("Failed to proceed to the next step")

以下是如何使用生成器执行相同的操作:

def my_iterator(value):
    while value > 0:
        yield value
        value -= 1

正如您所看到的,生成器使程序员的生活变得更加容易: - )