________在生成器和迭代器中__________和什么是方法包装器?

问题描述

特殊方法__iter____next__是创建迭代器类型的迭代器协议的一部分。为此,您必须区分两个独立的事物: 和 。

Iterables 有些事情可以重复,通常情况下,这些都是某种包含物品的容器元素。常见的例子是列表,元组或字典。

为了迭代可迭代对象,您可以使用 iterator 。迭代器是帮助您遍历容器的对象。例如,当迭代列表时,迭代器本质上会跟踪您当前所处的索引。

为了获得一个迭代器,在迭代器__iter__调用方法。这就像一个工厂方法,将为此特定可迭代方法返回一个新的迭代器。具有__iter__定义的方法的类型将其转换为可迭代的。

迭代器通常需要单个方法__next__方法返回迭代的 一项。另外,为了使协议更易于使用,每个迭代器也应该是可迭代的,并在__iter__方法中返回自身。

作为一个简单的示例,这可能是列表的迭代器实现:

class ListIterator:
    def __init__ (self, lst):
        self.lst = lst
        self.idx = 0

    def __iter__ (self):
        return self

    def __next__ (self):
        try:
            item = self.lst[self.idx]
        except IndexError:
            raise stopiteration()
        self.idx += 1
        return item

然后,列表实现可以简单地ListIterator(self)__iter__方法中返回。当然,列表的实际实现是在C中完成的,因此看起来有些不同。但是想法是一样的。

迭代器在Python中的各个地方都被不可见地使用。例如一个for循环:

for item in lst:
    print(item)

这与以下内容相同:

lst_iterator = iter(lst) # this just calls `lst.__iter__()`
while True:
    try:
        item = next(lst_iterator) # lst_iterator.__next__()
    except stopiteration:
        break
    else:
        print(item)

因此,for循环从可迭代对象请求一个迭代器,然后对其进行调用__next__,直到遇到stopiteration异常为止。这是在表面下发生的,这也是您还希望迭代器也实现的原因__iter__:否则,您将永远无法遍历迭代器。

对于生成器,人们通常所指的实际上是生成函数 ,即具有yield语句的某些函数定义。调用生成函数后,您将返回一个 generator生成器本质上只是一个迭代器,尽管它是花哨的(因为它比在容器中移动要多)。作为迭代器,它具有__next__生成”下一个元素的__iter__方法和返回自身的方法

生成函数的示例如下:

def exampleGenerator():
    yield 1
    print('After 1')
    yield 2
    print('After 2')

包含yield语句的函数主体将其转换为生成函数。这意味着在调用时,exampleGenerator()您将返回一个 生成 对象。Generator对象实现了迭代器协议,因此我们可以对其进行调用__next__(或使用next()上面的函数):

>>> x = exampleGenerator()
>>> next(x)
1
>>> next(x)
After 1
2
>>> next(x)
After 2
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    next(x)
stopiteration

请注意,第一个next()呼叫尚未打印任何内容。这是关于生成器的特殊之处:它们是惰性的,并且仅评估必要的内容以从迭代器中获取下一项。只有第二次next()调用,我们才能从函数体中获得第一条打印行。而且我们需要另一个next()调用来耗尽可迭代对象(因为没有其他值可产生)。

但是除了这种懒惰之外,生成器的行为就像可迭代的一样。stopiteration最后,您甚至会遇到一个异常,该异常允许将生成器(和生成函数)用作for循环源,并在任何可以使用“常规”可迭代项的地方使用。

发电机及其懒惰的最大好处是可以 按需 生产东西。一个很好的类比是在网站上无休止地滚动:您可以在之后(调用next()生成器)之后向下滚动项目,并且每隔一段时间,网站将不得不查询后端以检索更多项目以供您滚动浏览。理想情况下,这种情况不会引起您的注意。而这正是发电机的作用。它甚至允许这样的事情:

def counter():
    x = 0
    while True:
        x += 1
        yield x

非延迟的,由于这是一个无限循环,因此无法计算。但是懒惰地,作为生成器,有可能在一个项目之后消耗一个迭代的项目。我本来想让您不必将此生成器实现为完全自定义的迭代器类型,但是在这种情况下,这实际上并不是太困难,所以就来了:

class CounterGenerator:
    def __init__ (self):
        self.x = 0

    def __iter__ (self):
        return self

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

解决方法

我正在阅读有关生成器和迭代器以及的作用的信息__next__()

'__next__' in dir(mygen)。是真的

'__next__' in dir(mylist),是错误的

当我深入研究时,

'__next__' in dir (mylist.__iter__()) 是真的

  1. 为什么__next__只对列表中,但只有__iter__()mygen,但不会mylist。当我们使用list-comprehension遍历列表时如何__iter__()调用__next__

尝试手动使(+1)生成器步进,我致电mygen.__next__()。它不存在。它只存在于mygen.__next__所谓的方法包装器中。

  1. 什么是方法包装器?它有什么作用?在这里如何应用:mygen() and __iter__() ?

  2. 如果__next__Generator和Iterator都提供什么(及其唯一属性),那么Generator和Iterator之间有什么区别?*

答案3:已解决,如mod / editor所述:

Python的生成器和迭代器之间的区别

更新:生成器和迭代器都具有__next__()。我的错。查看日志,以某种方式mygen.__next__()测试给了我stopiteration异常错误。但是我无法再次复制该错误。

谢谢大家的回答!