Instructor: Hi, and welcome back.
In this video we're talking about
generator classes and iterators.
Here I'm gonna show you a class which implements
the 100 number generator we did in the last video.
So I'm gonna call it FirstHundredGenerator.
Like so, and then we're going to define an init method.
Which is just going to start the number off as zero,
and then we're going to define a next
underscore, underscore, next method.
When you define a next method in a class,
any object you can then call next of my object, like so.
So this is again, a dunder method that allows
you to call next on it.
It also tells Python something pretty important.
We're going to look at that in just a moment.
So, if we wanted to generate 100 numbers,
all that we have to do is get self.number,
return it, and increment it by one.
So, if self.number is less than 100,
we're not gonna use the yield keyword here,
by the way, because you don't need to in a class generator.
Sorry, in one of these things. (laughs)
I'm just going to not say anything that could
potentially be misconstrued as wrong.
Just so I don't confuse you.
What to do is, if the number is less than 100,
we put that in a variable,
then we increment the number by one,
and then we return the current number,
which was the previous value,
so that's zero.
We increment self.number by one, we return zero.
Okay.
Now important
on class
we have to,
if we want to stop returning numbers, like so,
we're not using a loop here to stop us when we reach 100.
So, when we reach 100 we have to raise
a special error which is called Stop Iteration.
Stop Iteration error tells Python
that we've reached the end of this generator.
I'm saying generator and I'm flinching slightly, um here.
Because this is essentially a generator in that,
you start at zero,
then you decide whether you want to return a new number,
you get that number, and then you return it,
and then the programme stops.
But your object remains, and it remembers self.number.
So, if we have my gen, and that's our first hundred
generator there.
My gen.number
is of course zero at the start.
Right?
Let's show you that.
My gen the number zero at the start.
If you do my gen.next
like so,
and then print my gen.number again,
you get one.
That makes sense right?
Because the next method here is checking
if the number is less than 100,
then incrementing it by one.
So these all make sense.
Now, in order to make it behave like a generator,
we just say next of my gen,
like so.
Then we can run this again, and the same thing comes out.
Of course, next of my gen is actually
returning the number that it had before we incremented it.
So instead of printing my gen.number here,
we can just print next of my gen,
and here we can also print next of my gen,
and we'll get the same output, zero and one.
The first time we call next, we get the current value,
which is zero, but we've incremented self.number by one.
The next time we call next,
we again, increments of that number by one,
but we'd return the previous value, which is one.
So now this is behaving exactly like a generator,
and indeed, this is a generator.
It's not storing all of the values up to 100 in a list.
It's giving you them one by one.
It's generating them as you call the next function.
Sorry, the next method.
By the way, dunder next is new in Python three.
So if you're using Python two,
you'll have to define next without the underscore.
That's only for Python two.
If you're using Python three use dunder next.
Okay,
All objects that have this dunder next method
are called iterators.
All generators, like this one, are iterators,
but not the other way around.
So you can have iterators that don't generate numbers.
For example, if you modifying your first number generator
to return part of a list like,
first hundred iterator, not generator,
you can have an init method here,
that says self.numbers is,
one, two, three, four, five.
Obviously it's not, not first hundred,
that's first five iterator, self I is zero.
So that's the index which you're gonna start returning.
Zero, and the numbers that we're returning
are from one to five.
Then again the next method here is just going to say
if I is less than len of self.numbers,
return self.numbers I.
Right?
Else raise stop iteration.
Sorry, you can't see that that well,
but there we go.
So all we're doing here is, we're not generating anything.
We're saying if I is less than,
by the way we have to, of course we have to do this,
I plus equal one,
and return current.
We have to increment one,
and we have to increment I by one of course.
Again, we're not generating new numbers.
We're keeping track of I, the index we're currently at,
you have to do that some how in order for,
this should be self.I by the way.
You can tell that I've not actually prepared this example,
but I just wanted to show you quickly that
not all generators, not all iterators,
have to be generators.
In this case, you're not generating the numbers,
you're returning them from a list.
So, just a quick example there.
You'll have this in the sample code for the section,
if I can remember to add it in.
So, that, here, what we do when we define the next method,
is we define an iterator,
something that you can go over one by one,
by calling the next function.
It doesn't necessarily have to generate all it's numbers,
but it can, but again, it can also return them from a list,
or from a sent, or anywhere else.
So, in Python it's important.
Iterators are those objects
that have a dunder next method.
You can call next on them.
We have ourselves an iterator,
but
we cannot do for I
in my gen,
in my gen.
You cannot do this.
Let me tell you that right now.
If we run this you get an error that says,
first 100 generator object is not iterable,
but I just said it's an iterator, and it is an iterator.
What an iterator means is you can call
the next function on it,
and it will give you the next value.
But an iterator and an iterable are different things.
You can iterate over an iterable,
and the iterator is used to get the next value
from a sequence or from generated values.
So what we've got ourselves here is an iterator
not an iterable.
We're gonna learn in the next video
how to create an iterable,
so that we can loop over it,
or indeed do things like sum of my gen,
or you know, whatever it is that you want to do.
List of my gen.
These things here need an iterable not an iterator.
So let's do that in the very next video.
I'll see you there.