当我从__next__里面屈服的时候。为什么它会返回生成器对象?

时间:2016-06-20 19:02:40

标签: python generator next

我使用yield来返回我班级 next 函数中的下一个值。但它不返回下一个值,它返回生成器对象。 我想更好地理解迭代器和产量。我可能会以错误的方式做到这一点。请看看。

class MyString:
    def __init__(self,s):
        self.s=s

    def __iter__(self):
        return self

    def __next__(self):
        for i in range(len(self.s)):
            yield(self.s[i])

r=MyString("abc")
i=iter(r)
print(next(i))

返回:

  

生成器对象__next__位于0x032C05A0

3 个答案:

答案 0 :(得分:10)

在这种情况下,

next几乎只调用__next__()。在你的对象上调用__next__将启动生成器并返回它(此时没有魔法)。

在这种情况下,您可能能够完全没有定义__next__

class MyString:
    def __init__(self,s):
        self.s=s

    def __iter__(self):
        for i in range(len(self.s)):
            yield(self.s[i])
        # Or...
        # for item in self.s:
        #     yield item

如果您想使用__iter____next__(定义{{​​3}}而不是简单地制作iterator),您可能想要做某事像这样:

class MyString:
    def __init__(self,s):
        self.s = s
        self._ix = None

    def __iter__(self):
        return self

    def __next__(self):
        if self._ix is None:
            self._ix = 0

        try:
            item = self.s[self._ix]
        except IndexError:
            # Possibly reset `self._ix`?
            raise StopIteration
        self._ix += 1
        return item

答案 1 :(得分:5)

让我们看一下__next__方法的目的。来自the docs

  

iterator .__ next __()

     

从容器中返回下一个项目。如果没有其他项目,请引发StopIteration异常。

现在让我们看看yield语句的作用。 the docs的另一段摘录:

  

在函数的主体中使用yield表达式会使该函数   成为发电机

  

调用生成器函数时,它将返回称为a的迭代器   发电机。

现在比较__next__yield__next__ 从容器中返回下一个项目。但是包含yield关键字的函数将返回迭代器。因此,在yield方法中使用__next__会导致产生迭代器的迭代器。


如果要使用yield来使您的类可迭代,请使用__iter__方法:

class MyString:
    def __init__(self, s):
        self.s = s

    def __iter__(self):
        for s in self.s:
            yield s

应该使用__iter__方法返回一个迭代器-并且yield关键字可以使它做到这一点。


为完整起见,这是使用__next__方法实现迭代器的方法。您必须跟踪迭代状态,并返回相应的值。最简单的解决方案可能是每次调用__next__时就增加一个索引:

class MyString:
    def __init__(self,s):
        self.s = s
        self.index = -1

    def __iter__(self):
        return self

    def __next__(self):
        self.index += 1

        if self.index >= len(self.s):
            raise StopIteration

        return self.s[self.index]

答案 2 :(得分:0)

据我所知,生成器函数只是具有 next 函数的类的语法糖。示例:

>>> def f():
    i = 0
    while True:
        i += 1
        yield i


>>> x = f()
>>> x
<generator object f at 0x0000000000659938>
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> class g(object):
    def __init__(self):
        self.i = 0

    def __next__(self):
        self.i += 1
        return self.i


>>> y = g()
>>> y
<__main__.g object at 0x000000000345D908>
>>> next(y)
1
>>> next(y)
2
>>> next(y)
3

事实上,我来这里的目的是看是否有显着差异。请大声喊叫。

因此,要回答这个问题,您所拥有的是带有__next__方法的类,该类返回一个也具有__next__方法的对象。因此,最简单的方法是将yield替换为return,并跟踪行进距离,并记住在到达数组末尾时引发StopIteration。像这样:

class MyString:
    def __init__(self,s):
        self.s=s
        self._i = -1

    def __iter__(self):
        return self

    def __next__(self):
        self._i += 1
        if self._i >= len(self.s):
            raise StopIteration
        return self.s[self._i]

这可能是实现我认为想要的最简单的方法。