 In this video, I'm going to explain to you what is the difference between the concept of an iterator and the concept of an iterable. Those two are often confused. It's actually quite easy to understand the difference. So I'm going to give you some background and then it should be straightforward. So let's create a new file and call it iterators versus iterables. Okay, so let's go ahead and first create a list of numbers and we are always going to use the same numbers. So 11, 11, 8, 5, 3, then we have 12 and 2, 6, 9 and 10 and 1 and 4. Okay, so numbers is a list object. And we said that any object over which we can loop is considered an iterable. Okay, so until now, let's put it this way, until now the definition was an iterable is any object over which we can loop. That is our working definition up to now. So just to prove it to you, it's going to be almost boring. If I say for number in numbers, just to illustrate the point, we can loop over numbers. Okay, so that's an iterable. Now the concept of an iterator is different. The concept of an iterator, what we have seen in previous videos, is any object that understands the next concept or it can work with the Python's built-in next function. So let's say an iterator is any object that may be passed as an argument to the built-in next function. So an example of that would be the following. Let's go ahead and get another example of the concept of a generator and also refute the generator expression syntax. So let's go ahead and simply write a generator with parentheses here. And we're simply going to write n squared for n in numbers. And maybe let's also go ahead and say if n, or if the number divided by 2 has no rest, so if the number is even. That creates a generator object and a generator object can be passed to the next built-in. So let's do that and I get the square of the first number here that is even. So the first even number is 8 and the square of that is 64. That is why we see 64. If I run it some second time I see 144 because 12 is the next even number and its square is simply 144. Okay, so let's try and see what happens if I pass to the next function the numbers list. I get a type error. So what do we learn from that? We learn from that that lists are not iterators. Okay, so that is already one difference. You know an iterable is not necessarily an iterator. The contrary, of course, however, is true. So let's go ahead and do the following. Let's say 4 square singular in Chen. Chen is the generator which creates squares. Let's simply go ahead and print the square. And let's do so, of course, only on one line. And we see the numbers 4, 36 and so on. So why 4? Well, I executed this cell here already twice. So I will go and do the next. So we already got the equivalent, the mapped value to 8 and 12. And the next even number would be 2 here. And the square of 2 would be 4. This is why we see 4. Then we see the next number is 6. The square of that would be 36. Okay, so what we want to remember from that here is that a generator can only go in one direction. So as we already got the first two numbers out of it, then the for loop can only continue where the generator has left off before. However, what we see from that code cell here is that we can indeed loop over an iterator. So what we can note down here is generators are iterable. Okay, so there is, of course, a connection between the two. And the connection is as follows. An iterable is any object over which we can loop. And the iterator is the thing that makes it loop. So let's go ahead and see what I mean by that. So I told you that an iterable is anything we can loop over and the iterator is what makes it loop. So let's go ahead and create an iterator out of an iterable. So numbers is, as we discussed, an iterable because I can loop over it. How can I get an iterator out of numbers? Well, there is a built-in function that we have not seen before. It is called iter. And before I execute that, let's go to the Python documentation under built-in functions and see what the documentation says. So it says we are given any object and it says return an iterator object and so on. So that is what the iter function does. So let's do that and let's store that in a variable that's called ListIterator. So first of all, let's look at the type of ListIterator. And the type of ListIterator happens to be ListIterator. I used the name of the type as the variable name. So maybe a better way to do that is to maybe simply call it it as a short version. And then the type of it is of course also ListIterator. And so now what can it do? Well, it is an iterator. So if I say next and I pass to it it as the argument, I get back to number 7. Why 7? Well, obviously, the number 7 is the first number in the list. So let's go ahead and I call next one more time and I get the number 11. So indeed, the iter function takes an iterable as its input and it gives me back an object that makes the iteration work. So that basically what the it object here is, it is an object, a rule in memory, that remembers the last number you pulled out of the list. And it always remembers the last one. And when you call next with it, then really what's going on is you just get the next number. And really to be even more into more detail, what it does, it simply remembers the last index or the index of the last element you pulled out. So let's do something to play some tricks with it. So let's maybe go ahead and now the last number I pulled out was number 11. So the third number in here is the number 8, which is index 2. So let's overwrite that number with to be 99, for example. If I now go ahead and say next it, then I'm going to see the number 99. Okay. So in other words, the list and the list iterator are two different objects. That may be confusing. So at some point, so maybe let's do the following. Let's go ahead and also use Python tutor to illustrate that. It is really quite simple, but just to make sure that you get it, I put a list here and let's go down and create the iterator in a separate line here. And let's go ahead and first numbers is a full list object. And the it object is simply a list iterator instance. It says here. So it's a second object. And all the object does is it remembers where in the iteration you are. Okay. The iterator is kind of like the manager that manages the iteration process. And if we change the list, the underlying list, then the iterator does not even know about that. So just as we saw in Jupyter lab here, when I change some of the underlying elements in the list, the iterator simply returns it in this case here. Okay. So that's the difference between iterator and iterable. So maybe I give you a better definition and iterable with any function as any object, sorry, that may be passed as an argument to the built in iter function. Okay. So that is probably the better definition. But as a beginner, when you start out with Python, I don't want to confuse you. So I gave you the easy definition and iterable is any object over which I can loop. That's kind of the approximate definition. And now the precise definition is simply an iterable with any object that may be passed to the iter function, which I did right here. And then I get back an iterator. And what is an iterator? Well, an iterator is any object that I can pass to the built in next function. Okay. And we have seen a couple of iterators already. We have seen map objects. We have seen filter objects. We have seen generator objects. These are all iterators. And now we have a fourth example of an iterator, which happens to be the list iterator. So maybe to conclude this video, I will explain to you how the for loop really works behind the scenes. So in many other programming languages, the for loop is not as flexible as Python's for loop. So why is Python's for loop so flexible? The reason is behind the scenes it does the following. So let's assume I have given a numbers list. And let's say I want to write the following for number in numbers and then simply print number. And let's put all of that on one line. So that is the for loop. And now let's rewrite that using a while loop and see what really goes on behind the scenes in Python. So what goes on is as follows. Python first goes ahead and creates an iterator out of the numbers object. So right here, this is the target. Numbers is the target of the for loop over which we loop. So this the target is used as the argument behind the scenes and passed to the iter function. This gives me back an iterator object. And then what is going to happen is the following. Python behind the scenes will initialize or start an indefinite loop. You remember that from the chapter on indefinite loop and where we talked about guessing games. So it creates a while loop, a while true loop behind the scenes. And then in the while true loop we have a try statement and you will see why in a bit. And we are going to go ahead and in this case because we call this variable here number singular. I'm also going to call it right here number singular. And how do we get number singular? Well, by simply asking what is the next element that the iterator that we created before the while loop returns. Now we know that the next function at some point will give us a so-called stop iteration exception. Whenever the iterator is exhausted, then we get the red error message where it says stop iteration. And now this one we have to accept it. So we don't want to see the stop iteration exception. So maybe let's do that. So accept stop iteration here. And what do we want to do when we see the stop iteration exception? Well, we want to stop the for loop, right? So in other words, we want to break out of the while loop here. And then there is of course also an else clause. The else clause is whatever happens when no exception is triggered. And here we will simply put the code to be repeated. So maybe right here code to be repeated because for loops are all about repeating code. And of course, the while loop is also about repeating code. And let's do it like that. And we see we get the exact same outcome here. Okay, and that is not an accident. So in other words, when we in chapter four, we talked about the idea that the for loop is really just a special case of a while loop. That is what I told you. And here you see why. So whenever we initialize a for loop in Python, what goes on behind the scenes is really a while loop. And Python goes ahead and calls the iter function with the thing we want to loop over the iterable. And then it uses the iterator to loop over everything and implement the loop. So we see here by writing a for loop, I have one line for managing the iteration. And then I have the line that is repeated inside the for loop. And here I would have, I don't know, two, five, six, it's seven lines, seven lines of code that do the same thing. So really the for loop is just an abbreviation for all of the things you can read here. Okay, so you don't have to know that. This is something that you will never see in practice, but this is just to get you, give you some further example of how iterators and iterables relate to each other. Okay, so what we learned from that is an iterable, if anything, we can loop over. But more precisely, an iterable is anything that gives me back an iterator. And the iterator is the thing, the rule in memory that makes the looping work. And when we use a for loop, everything is done for us by Python. But as we saw with the generator expression and also the map and filter types, we can also use these rules in memory ourselves without a for loop. So at the end of the day, from day one in this course, you have already been using iterators all the time. Every time you use the for loop, you were using iterators. And now in chapter eight, you learned what they are. And I know that iterators or generators, in particular, in the beginning, they are a bit scary to beginners. But really, this is just how Python is built. So iterators, generally speaking, are just rules that know one thing and one thing only. Give me back the next element in the line. Okay, so that is the comparison between iterators and iterables. So you remember that iterables are not iterators, but all iterators are always iterable. Okay, because we saw here that we can loop over an iterator, of course. Okay, so I hope I did not mix up the two words in this video. It's quite hard to speak about that. But yeah, the concepts are now, I guess, pretty clear. So I will see you in the next video where we compare the sorted and the reverse built-ins because one of them also has to do with an iterator behind the scenes. Okay, so I will see you in the next video.