"Fluent python" learning notes: iteratable objects, iterators and generators


Iteratable objects, iterators, generators, I don't know if you have a very familiar feeling when you first see these nouns, and then quickly look for the differences between these words in your mind, but after looking for a long time, you don't seem to find it, and the original clear concept becomes blurred.

Anyway, I had this feeling at the beginning, but now I still feel a little dizzy after reading this chapter. Hahaha, but I'd better take advantage of the hot iron and review and consolidate it. It should be clearer!

First of all, let's take a look at their respective definitions. Here I will refer to the contents of the book, and then define the three in combination with my own understanding.

Iteratable object

First, we can ask such a question: what is an iteratable object? This may be more abstract and difficult to understand. Let's put it another way: what behavior objects are iteratable objects? In this way, you may be much clearer (thanks to the advantages of python itself: in python, when we say what an object belongs to, we don't look at its definition, but what kind of behavior it has).

Here are some chestnuts:

a = [1, 2, 3]  # list
b = 'hello'  # character string
class Fruit:  # class
    fruits = ['apple', 'peach', 'banana']

    def __getitem__(self, item):
        return self.fruits[item]

if __name__ == '__main__':
    for i in a: print(i, end=' ')
    for i in b: print(i, end=' ')
    for i in Fruit(): print(i, end=' ')

The list can be traversed, so it can be iterated and is an iteratable object;

It can iterate, so it can iterate;

Why can Fruit objects also be traversed? "Fluent python" learning notes: eccentric python? You may find the answer in this article!

So let's summarize: objects that can iterate over the values in an object by using a for like loop are iteratable objects. What are the unique methods or properties of these objects?

Generally speaking, objects with the following properties or methods are iteratable objects:

  • Realized__ iter__ Object of method
  • Implemented__ getitem__ Object of method
  • Sequences (such as list, str, array, dict, set, etc.) are iteratable objects

An object that satisfies any of the above three conditions is an iteratable object!


From the definition of the interface, an iterator is an object that implements parameterless__ next__ Method to return the next element in the sequence; If there are no elements, a StopIteration exception is thrown.

The definition of iterator is relatively simple, which can be summarized in one sentence: as long as it is implemented__ next__ All objects are iterators! (of course, _next _'s behavior is to get the next element!)

Here is a chestnut:

import re
import reprlib
from typing import Iterator

class Sentence:
    RE_WORD = re.compile('\w+')

    def __init__(self, text):
        self.text = text
        self.words = self.RE_WORD.findall(self.text)

    def __getitem__(self, item):
        return self.words[item]

    def __len__(self):
        return len(self.words)

    # reprlib.repr is used to generate a short string representation of large data structures
    def __repr__(self):
        return f'Sentence({reprlib.repr(self.text)})'

    def __iter__(self):
        return SentenceIterator(self.words) #Convert to iterator

class SentenceIterator:

    def __init__(self, words):
        self.words = words
        self.index = 0

    def __next__(self):

            word = self.words[self.index]
        except IndexError:
            raise StopIteration()

        self.index += 1
        return word

    def __iter__(self):
        return self

if __name__ == '__main__':
    text = 'we price the things when we have lost them.'
    sentence = Sentence(text)
    sentence_iter = sentence.__iter__()  # Call__ iter__ Method to iterator

    print(isinstance(sentence_iter, SentenceIterator)) #The result is True
    while True:
            print(next(sentence_iter),end=' ') #Value through next

You can see that the object of sentinceiterator is a typical iterator because it implements__ next__ method!


There are two ways to get the generator:

  1. Generated by a function containing the yield keyword
  2. Generated by generator expression

Take chestnuts for example:

#generator function 
def func():
    for i in range(10):
        yield i

if __name__ == '__main__':
    a = (i for i in range(10)) #Generator Expressions 


You can see that the objects obtained through the function func and generator expression belong to the generator class and are generator objects, and you can get the next element through the next() method! So there's another conclusion: all generators are iterators!



Of these three objects, the iteratable object may be the best understood. The iterator and generator may always feel the same. From the definition of the interface, we can see that both iterator and generator are implemented__ next__ Method, so it can be said that the generator is also an iterator, but in terms of definition, there are only those two definition methods of the generator, which is also a special definition method. This may be the difference between the generator and the iterator (at least in terms of behavior and performance).

However, in the essay at the end of this chapter, the author mentioned that in fact, python programmers do not strictly distinguish between the two. Even in the official documents, generators are called iterators, and iterators and generators are synonymous to some extent.

Therefore, if you still feel a little dizzy here, just don't tangle anymore. Just treat the generator and iterator as a pair of twins! Who makes their behavior so similar?

Welcome to leave a message in the comment area to discuss your opinions on these three~

Synchronous update to personal blog system: "Fluent python" learning notes: iteratable objects, iterators and generators

Posted by kungfu71186 on Mon, 18 Apr 2022 10:07:08 +0930