生成器和迭代器中的__next__以及什么是方法包装器? [英] __next__ in generators and iterators and what is a method-wrapper?

查看:160
本文介绍了生成器和迭代器中的__next__以及什么是方法包装器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读有关生成器和迭代器以及 __ next __()的作用。

I was reading about generator and iterators and the role of __next__() .

dir(mygen)中的__ next__。是真的

dir(mylist)中的'__ next__',是假的

当我深入研究它时,

'__ next__'在dir(mylist .__ iter __())是真的


  1. 为什么 __ next __ 仅供列表使用但仅限 __ iter __() mygen 但不是 mylist __ iter __()当我们使用list-comprehension踩到列表时,如何调用 __ next __

  1. why is__next__ only available to list but only to __iter__() and mygen but not mylist. How does __iter__() call __next__ when we are stepping thru the list using list-comprehension

尝试手动步进(+1)发电机,我打电话给 mygen .__ next __()。它不存在。它只存在于 mygen .__ next __ ,它被称为method-wrapper。

Trying to manually step (+1) up the generator, I called mygen.__next__(). It doesn't exist. It only exist as mygen.__next__which is called method-wrapper.

什么是方法 - 包装,它做什么?它是如何应用的:在 mygen()和__iter __()?

what is a method-wrapper and what does it do? How is it applied here: in mygen() and __iter__() ?

如果 __ next __ 是生成器和迭代器提供的(以及它们的唯一属性)那么生成器和迭代器之间有什么区别?*

if __next__ is what both generator and iterator provide (and their sole properties) then what is the difference between generator and iterator?*

回答3:解决,如mod /编辑所述:

Answer to 3: Solved, as noted by mod/editor:

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

更新:发生器和迭代器有 __ next __()。我的错。看着日志,莫名其妙地 mygen .__ next __() test给了我停止异常错误。但我无法再次复制该错误。

UPDATE: both generator and iterator have __next__(). My mistake. Looking at the logs, somehow mygen.__next__() test was giving me stopiteration exception error. But I wasn't able to duplicate that error again.

感谢大家的回答!

推荐答案

特殊方法 __ iter __ __ next __ 是创建迭代器类型。为此,您必须区分两个不同的东西: Iterables 迭代器

The special methods __iter__ and __next__ are part of the iterator protocol to create iterator types. For this purpose, you have to differentiate between two separate things: Iterables and iterators.

Iterables 是可以迭代的东西,通常,这些是包含项目的某种容器元素。常见示例是列表,元组或字典。

Iterables are things that can be iterated, usually, these are some kind of container elements that contain items. Common examples are lists, tuples, or dictionaries.

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

In order to iterate an iterable, you use an iterator. An iterator is the object that helps you iterate through the container. For example, when iterating a list, the iterator essentially keeps track of which index you are currently at.

要获取迭代器, __ iter __ <在$ iterable上调用/ code>方法。这就像一个工厂方法,它为这个特定的iterable返回一个新的迭代器。定义了 __ iter __ 方法的类型,将其转换为可迭代类型。

To get an iterator, the __iter__ method is called on the iterable. This is like a factory method that returns a new iterator for this specific iterable. A type having a __iter__ method defined, turns it into an iterable.

迭代器通常需要一个方法, __ next __ ,返回迭代的 next 项。另外,为了使协议更容易使用,每个迭代器也应该是一个可迭代的,在 __ iter __ 方法中返回自己。

The iterator generally needs a single method, __next__, which returns the next item for the iteration. In addition, to make the protocol easier to use, every iterator should also be an iterable, returning itself in the __iter__ method.

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

As a quick example, this would be a possible iterator implementation for a list:

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中完成的,所以这看起来有点不同。但是这个想法是一样的。

The list implementation could then simply return ListIterator(self) from the __iter__ method. Of course, the actual implementation for lists is done in C, so this looks a bit different. But the idea is the same.

迭代器在Python的各个地方都是不可见的。例如 for loop:

Iterators are used invisibly in various places in Python. For example a for loop:

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 __ on可迭代,直到它达到 StopIteration 异常。这种情况发生在表面之下也是你希望迭代器实现 __ iter __ 的原因:否则你永远不能遍历迭代器。

So the for loop requests an iterator from the iterable object, and then calls __next__ on that iterable until it hits the StopIteration exception. That this happens under the surface is also the reason why you would want iterators to implement the __iter__ as well: Otherwise you could never loop over an iterator.

对于生成器,人们通常所指的实际上是生成器 function ,即某些函数定义 yield 语句。一旦调用该生成器函数,就会返回生成器。一个生成器实际上只是一个迭代器,虽然它很奇特(因为它不仅仅是通过容器移动)。作为迭代器,它有一个 __ next __ 方法来生成下一个元素,并有一个 __ iter __ 方法返回自己。

As for generators, what people usually refer to is actually a generator function, i.e. some function definition that has yield statements. Once you call that generator function, you get back a generator. A generator is esentially just an iterator, albeit a fancy one (since it does more than move through a container). As an iterator, it has a __next__ method to "generate" the next element, and a __iter__ method to return itself.

示例生成器函数如下:

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

包含 yield 语句的函数体转为此进入发电机功能。这意味着当你调用 exampleGenerator()时,你会得到一个生成器对象。 Generator对象实现迭代器协议,因此我们可以在其上调用 __ next __ (或使用 next()函数作为上述):

The function body containing a yield statement turns this into a generator function. That means that when you call exampleGenerator() you get back a generator object. Generator objects implement the iterator protocol, so we can call __next__ on it (or use the the next() function as above):

>>> 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()调用以消耗迭代(因为没有产生另一个值)。

Note that the first next() call did not print anything yet. This is the special thing about generators: They are lazy and only evaluate as much as necessary to get the next item from the iterable. Only with the second next() call, we get the first printed line from the function body. And we need another next() call to exhaust the iterable (since there’s not another value yielded).

但是除了那种懒惰,发电机就像迭代一样。你甚至在最后得到一个 StopIteration 异常,它允许生成器(和生成器函数)用作用于循环源和任何可以使用正常迭代的地方。

But apart from that laziness, generators just act like iterables. You even get a StopIteration exception at the end, which allows generators (and generator functions) to be used as for loop sources and wherever "normal" iterables can be used.

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

The big benefit of generators and their laziness is the ability to generate stuff on demand. A nice analogy for this is endless scrolling on websites: You can scroll down item after after (calling next() on the generator), and every once in a while, the website will have to query a backend to retrieve more items for you to scroll through. Ideally, this happens without you noticing. And that’s exactly what a generator does. It even allows for things like this:

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

非懒惰,这是不可能的计算,因为这是一个无限循环。但懒洋洋地说,作为一个生成器,可以在一个项目后使用这个迭代的一个项目。我原本想让你免于将这个生成器实现为一个完全自定义的迭代器类型,但在这种情况下,这实际上并不太难,所以在这里:

Non-lazy, this would be impossible to compute since this is an infinite loop. But lazily, as a generator, it’s possible to consume this iterative one item after an item. I originally wanted to spare you from implementing this generator as a fully custom iterator type, but in this case, this actually isn’t too difficult, so here it goes:

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

    def __iter__ (self):
        return self

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

这篇关于生成器和迭代器中的__next__以及什么是方法包装器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆