At the beginning of this chapter, I told you that generator objects are based on the iteration protocol. We'll see in Chapter 6, OOP, Decorators, and Iterators a complete example of how to write a custom iterator/iterable object. For now, I just want you to understand how next() works.
What happens when you call next(generator) is that you're calling the generator.__next__() method. Remember, a method is just a function that belongs to an object, and objects in Python can have special methods. __next__() is just one of these and its purpose is to return the next element of the iteration, or to raise StopIteration when the iteration is over and there are no more elements to return.