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 for loop calls Fib(1000), as shown. This returns an instance of the Fib class. Call this fib_inst.
  • Secretly, the for loop calls iter(fib_inst), which returns an iterator object. Call this fib_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 to n
  • When next(fib_iter) raises a StopIteration exception, the for loop will swallow the exception and gracefully exit.

results matching ""

    No results matching ""