Q. Generator
Generators are just a simple form of iterators. A function that yields values is a nice, compact way of building an iterator without building an iterator.
# A Fibonacci Generator
def fib(max):
a, b = 0, 1
while a < max:
yield a
a, b = b, a + b
the yield keyword in fib() means that this is not a normal function. It is a special kind of function which generates values one at a time.
for n in fib(100):
print\(n, end=' '\)
You can use a generator like fib() in a forloop directly. The for loop will automatically call the next() function to get values from the fib() generator
Q. Iterator
Iterators are the “secret sauce” of Python 3. They’re everywhere, underlying everything, always just out of sight. Comprehensions are just a simple form of iterators. Comprehensions are just a simple form of iterators
class Fib:
'''iterator that yields numbers in the Fibonacci sequence'''
def __init__(self, max):
self.max = max
def __iter__(self):
self.a = 0
self.b = 1
return self
def __next__(self):
fib = self.a
if fib > self.max:
raise StopIteration
self.a, self.b = self.b, self.a + self.b
return fib
The __init__() Method
The __init__() method is called immediately after an instance of the class is created.
The first argument of every class method, including the __init__() method, is always a reference to the current instance of the class. By convention, this argument is named self.
The __iter__() method
The __iter__() method is called whenever someone calls iter(object_instance) , a forloop will call this automatically, but you can also call it yourself manually.
the __iter__() method usually do
- beginning-of-iteration initialization (iteration 開始前的初始化)
- return any object that implements a
__next__()method.
The __next__() method
The __next__() method is called whenever someone calls next(fib_iter) on an iterator of an instance of a class.
When the __next__() method raises a StopIteration exception, this signals to the caller that the iteration is exhausted. If the caller is a for loop, it will notice this StopIteration exception and gracefully exit the loop.
To spit out the next value, an iterator’s __next__() method simply returns the value. Do not use yield here. yield 只是generator 專用的 syntax sugar
How to use Fib iterator ?
for n in Fib(1000):
print(n, end=' ')
# output here ...
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
There’s a bit of magic involved in for loops. Here’s what happens:
- The
forloop callsFib(1000), as shown. This returns an instance of the Fib class. Call thisfib_inst. - Secretly, the for loop calls
iter(fib_inst), which returns an iterator object. Call thisfib_iter. In this case, fib_iter == fib_inst - To“loop through” the iterator, the for loop calls
next(fib_iter), which calls the__next__()method on the fib_iter object, which does the next-Fibonacci-number calculations and returns a value. The for loop takes this value and assigns it ton - When
next(fib_iter)raises aStopIterationexception, theforloop will swallow the exception and gracefully exit.