您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

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

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

特殊方法__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
其他 2022/1/1 18:34:37 有534人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶