简体   繁体   中英

Confused about “iterators” in python

I am studying python with the book Beginning Python: From Novice to Professional , and I get confused about the section discussing iterators . There is an example in this section:

>>> Class Fibs:
...    def __init__(self):
...        self.a = 0
...        self.b = 1
...    def __next__(self):
...        self.a, self.b = self.b, self.a + self.b
...        return self.a
...    def __iter__(self):
...        return self
...
>>> fibs = Fibs()
>>> for f in fibs:
...     if f > 1000:
...         print(f)
...         break
...
1597

To be honest, I only know that fibs is an object with methods __next__ and __iter__ , but have no idea about what happens in each step of the loop. And I made a test:

>>> isinstance(f, Fibs)
False
>>> f is fibs
False
>>> isinstance(f, int)
True
>>> fibs.a
1597

This makes me much more confused! Why the boolean value of f is fibs is False ? And why fibs.a become 1597 after the execution of the loop?(Is the method __next__ automatically called in the loop?) Thanks in advance.

 1  fibs = Fibs()
 2  for f in fibs:
 3      if f > 1000:
 4          print(f)
 5          break

Line 1 creates a Fibs() object, calling __init__() . Line 2 calls __iter__() , which returns an iterator object (in this case, just fibs itself). The interpreter will then begin calling the __next__() method repeatedly; it returns self.a , a plain number, which is assigned to the loop variable f (so of course it's not a Fibs() object and certainly not the one named fibs). When that value reaches 1000, the if clause will fire, print the result, and break out of the loop.

And why fibs.a become 1597 after the execution of the loop?

Well this is because it is going through the Fibonacci sequence and this is the first number over 1000 in the sequence.

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597 , 2584 ...

On enter to the loop interpreter calls __iter__ method. On every loop step interpreter calls __next__ method of Fibs .

Yes, the loop automatically calls __next__ .

The for loop does this to the given object:

# turn the object into an iterator
iterator = iter(given_object)
while True:
    try:
        # try to get the next value
        next_value = next(iterator)
    except StopIteration
        # for loop is done, run the `else:` block if there is any
        run_for_else_suite()
        break
    else:
        # set the loop target to `next_value`
        assign_next_value(next_value)
        continue = run_loop_body()
        if not continue:
            break

The iter() function calls given_object.__iter__() , and the next() function calls given_object.__next__() ; these functions offer some extra functionality and are the proper way of calling into the iterator API.

So, in each loop iteration, f is assigned the value that the Fib.__next__ method returned.

You can also see that Fib is its own iterator; __iter__ returns self . Other types can return a dedicated iterator object; lists do, for example:

>>> iter([])
<listiterator object at 0x129516610>

Returning dedicated iterators lets you create multiple 'views' on an object where each iterator maintains its own position, like nested loops:

lst = [1, 2, 3]
for i in lst:
    for j in lst;
        print (i, j)  # prints (0, 0), (0, 1), (0, 2), (0, 3), (1, 0), etc.

or you can explicitly reuse the iterator:

lst = [1, 2, 3]
lst_iter = iter(lst)
for i in lst_iter:
    for j in lst_iter:
        print (i, j)  # prints (0, 1), (0, 2)
for f in fibs

implicitly calls fibs.__iter__ and binds f to all the objects that it yields, in turn. None of these objects are instances of Fibs , let alone equal to fibs . The whole is (roughly) equivalent to

# boilerplate, implicit in the "for" notation
__iterator = iter(fibs)
while True:
    try:
        f = next(__iterator)
    except StopIteration:
        break

    # your code, with f now bound to what the iterator yielded
    if f > 1000:
        print(f)
        break

( iter and next are the clean ways to call __iter__ and __next__ , respectively.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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