python迭代器,生成器及其之间

问题描述 投票:1回答:2

因此,我得到了用于延迟求值和生成器表达式的生成器函数,又称生成器理解为它的语法糖等效项。

我了解类似的类

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__()

打印语句仅在首次调用next()时执行。这是由于产量和迭代率的奇怪混合造成的吗?我认为这与直觉相悖...

python iterator generator
2个回答
1
投票

等效于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的实例),因此它们无法独立地遍历数据。

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


1
投票

在任何函数中的任何地方都具有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

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

© www.soinside.com 2019 - 2024. All rights reserved.