I am trying to wrap my head around this phrase:
Every iterator is an iterable, but not every iterable is an iterator.
I understand the difference between an Iterator and Iterable, and I understand the last part that "not every iterable is an iterator".
An iterable is a sequence that can be iterated over. An Iterator is an object that is used to iterate over an iterable.
An Iterable produces an Iterator object through the __iter__()
So, how can an Iterator be an Iterable if the Iterator itself is what is used to iterate over something?
Help me make sense of this. Thank you! .
.
UPDATE 1: Found Answer
First, I want to thank all those who gave a response to my question. However, as helpful, informative, and insightful as it all was, it didn't exactly answer my question.
ANSWER & EXPLANATION 1:
First, the use of the term "Iterable" in the phrase "Every Iterator is an Iterable" was not meant to identify an Iterator as an Iterable object like a list, dictionary, or set. It was meant to say that an Iterator also contains an __iter__()
method.
Then my next question was: why in the world would an Iterator object have an __iter__()
method? The only purpose of the Iterator object is to use its __next__()
method.
Then I found the answer to my question in one line:
Why Python Iterator need a dunder iter function
"Because sometimes you're directly given iterators, for example an opened file or a generator function."
We have to remember that a loop first has to call the __iter__()
method of the object that it is given in order to receive the Iterator object for iteration.
But, again, there are situations where you are given an Iterator object directly. And in order to use that Iterator object in a loop for iteration, we need to figure out how to bypass the __iter__()
method call that the loop automatically performs. So, the Iterator object is packed with its own __iter__()
method that returns itself.
Bingo Bango! your in! Loophole activated. The iteration starts as if the loop was dealing with the Iterable object directly. .
.
UPDATE 2: Answered Continued
A fellow user kindly asked for me to complete the interpretation of the phrase above.
ANSWER & EXPLANATION 2:
First part of the phrase:
Every Iterator is an Iteratable...
Interpretation:
Every Iterator has an
__iter__()
method
Second Part of the phrase
but not every Iterable is an Iterator
Interpretation:
but not every Iterable has a
__next__()
method
In python, there are objects that have both an __iter__()
and a __next__()
method. These objects are both an Iterable and an Iterator. In these objects, the __iter__()
method returns itself because it is its owns Iterator (of course).
Example:
class MyRange:
def __init__(self, start, end):
self.value = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.value >= self.end:
raise StopIteration
current = self.value
self.value +=1
return current
Usage:
nums = MyRange(1,10)
for num in nums:
print(num)
Now...
Objects like list, dictionary, tuple, and set are only Iterables. These objects only have an __iter__()
method, and it returns a separate object (Iterator) that has the __next__()
method.
....and thats it!
I apologize if my explanations are too simplistic or obvious. My explanations are aimed at beginner programmers (like me) who can't connect the dots so intuitively like others can.
Anyways, I hope this helps someone. Cheers!