繁体   English   中英

python迭代器、生成器以及介于两者之间

[英]python iterators, generators and in between

所以我得到了用于惰性求值和生成器表达式的生成器函数,也就是生成器推导式作为它的语法糖等价物。

我理解类

class Itertest1:
    def __init__(self):
        self.count = 0
        self.max_repeats = 100

    def __iter__(self):
        print("in __inter__()")
        return self

    def __next__(self):
        if self.count >= self.max_repeats:
            raise StopIteration
        self.count += 1
        print(self.count)
        return self.count

作为实现迭代器接口的一种方式,即iter ()和next ()在同一个类中。

但那是什么

class Itertest2:
    def __init__(self):
        self.data = list(range(100))

    def __iter__(self):
        print("in __inter__()")
        for i, dp in enumerate(self.data):
            print("idx:", i)
            yield dp

它在iter成员函数中使用了 yield 语句?

我还注意到在调用 iter 成员函数时

it = Itertest2().__iter__()
batch = it.__next__()

print语句只在第一次调用next ()时执行。 这是由于收益率和迭代的这种奇怪的混合吗? 我认为这很违反直觉......

在任何函数中的任何位置都有yield语句将函数代码包装在(本机)生成器对象中,并用一个存根替换该函数,该存根为您提供所述生成器对象。

因此,在这里,调用__iter__将为您提供一个执行所需代码的匿名生成器对象。

__next__的主要用例是提供一种无需依赖(本机)生成器即可编写迭代器的方法。

__iter__的用例是区分对象和该对象上的迭代状态。 考虑像这样的代码

c = some_iterable()
for a in c:
    for b in c:
        # do something with a and b

您不希望两个交错的迭代干扰彼此的状态。 这就是为什么这样的循环会脱糖成类似的东西

c = some_iterable()
_iter1 = iter(c)
try:
    while True:
        a = next(_iter1)
        _iter2 = iter(c)
        try:
            while True:
                b = next(_iter2)
                # do something with a and b
        except StopIteration:
            pass
 except StopIteration:
     pass

通常,自定义迭代器实现一个返回self的存根__iter__ ,因此iter(iter(x))等价于iter(x) 这在编写迭代器包装器时很重要。

可以使用单独的迭代器类编写与Itertest2等效的东西。

class Itertest3:
    def __init__(self):
        self.data = list(range(100))

    def __iter__(self):
        return Itertest3Iterator(self.data)


class Itertest3Iterator:
    def __init__(self, data):
        self.data = enumerate(data)

    def __iter__(self):
        return self

    def __next__(self):
        print("in __inter__()")
        i, dp = next(self.state)  # Let StopIteration exception propagate
        print("idx:", i)
        return dp

与此相比, Itertest1 ,其中的实例Itertest1本身承载的迭代周围的状态。 Itertest1.__iter__每次调用Itertest1.__iter__返回相同的对象( Itertest1的实例),因此它们无法独立迭代数据。

请注意,我将print("in __iter__()")放在__next__ ,而不是__iter__ 正如您所观察到的,在第一次调用__next__之前,生成器函数中的任何内容实际上都不会执行 生成器函数本身创建一个生成器; 它实际上并没有开始执行其中的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM