先上样例:

class Fib:
    def __init__(self,max):
        self.max = max

    def __iter__(self):
        iter_fib = Iter_Fib(self)
        return iter_fib

class Iter_Fib:
    def __init__(self,fib):
        self.fib = fib
        self.a = 0
        self.b = 1

    def __next__(self):
        num = self.a
        if num > self.fib.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return num

# explicitly called
fib = Fib(10)
fib_iter = iter(fib)
print(next(fib_iter))
print(next(fib_iter))
print(next(fib_iter))

# implicitly called in for loop
fib = Fib(100)
for i in fib:
    print(i)

Fib是主类,Iter_Fib是对应的迭代器类,我们说Fib是一个有迭代器的类,因为Fib中定义了__iter__方法。在主类对象上调用__iter__方法 返回一个对应的迭代器对象。

迭代器类需要定义__next__方法,返回值就是在迭代器上调用next()时要返回的下一个值。如果没有值了,要raise StopIteration异常。

显式调用的情况比较明显,在主类对象上调用iter()得到迭代器对象,在迭代器对象上调用next()得到下一个值,没有值时会触发StopIteration异常 。隐式调用的情况比较有趣,可以直接用_for i in 主类对象_这种形式。iter()和next()都会被自动调用,而且没有值时的StopIteration异常会被for loop当作False从而循环结束,并不会抛出。

下面扯点和迭代器相关但不完全一样的。

generator function是包含了yield语句的函数,特点会生成一个generator object。可以对这个generator object调用next()方法得到一系列生成的值。这些值的生成的方法就是运行generator function,遇到yield的话就把yield后面的表达式的值输出,并将状态暂存,直至下一次调用next()。多个generator object不会互相冲突。例如:

def make_gen():
    i = 0
    while True:
        yield i
        i += 1

g = make_gen()
next(g)
next(g)
next(g)
h = make_gen()
next(h)
next(h)

generator expression看上去与list comprehension相仿,只是把方括号变成圆括号,如:

g = (i for i in lst)

同样可以在generator expression上调用next()方法,没有值了会抛出StopIteration异常,不细说了。