0

I am confused about iterator in python. Please take a look on the code.

class MyNumbers:
  def __init__(self):
     self.a=4
  def __iter__(self):
    return self

  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration

myclass = MyNumbers()
myiter1 = iter(myclass)
c=list(myiter1)
for x in myiter1:
  print(x)

I getting no output from the above code. I was expecting some value iteration from 4. but when i was removing c=list(myiter1) i was getting expected output. So i am confused about it. why is it happening.

  • `y=self.b` it where is b defined? – Epsi95 Jul 05 '21 at 14:46
  • 2
    by `c=list(myiter1)` you are already exhausting the iterator, that is why the loop not working. Check by `next(myiter1)` it should throw `StopIteration` exception after `list(myiter1)`, which means it is exhausted. – Epsi95 Jul 05 '21 at 14:47
  • If you remove line `c=list(myiter1)` then the loop prints the values in the iterator – CodeMonkey Jul 05 '21 at 14:49
  • while editing the code i forget to remove `y=self.b`. What does it meant by exhausting the iterator @Epsi95 – sachin rawat Jul 05 '21 at 14:49
  • If want creation of iterator to reset itself each time then add `self.a = 4` to __iter__ function. – CodeMonkey Jul 05 '21 at 14:57
  • One thing to mention that you are wrongly applying `iter()` on `myclass`. A class that implements both `__iter__` and `__next__` is an `iterator`, so you can directly loop through it. But it not necessarily the case, `iter()` is called on `iterable` to get iterator` For example `list` is an iterable, so you can't do `next()` on list directly, you need to get the iterator by `iter(your_list)`. `list(something)`, `for in something` calls `iter(something` under the hood – Epsi95 Jul 05 '21 at 14:58

1 Answers1

2

Your iterator is exhausted: list in the assignment to c consumed all the available values, resulting in a list [4, 5, 6, ..., 20] and an iterator that will raise StopIteration immediately when you try to iterate over it again.

You may be confused because it appears you can iterate over a list multiple times. But that is because a list itself is not an iterator.

>>> list.__next__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'list' has no attribute '__next__'

Calling iter on a list produces a list_iterator value, not the list itself. That iterator is exhaustible like any other iterator.

>>> x = [1,2,3]
>>> y = iter(x)
>>> type(y)
<class 'list_iterator'>
>>> list(y)
[1, 2, 3]
>>> list(y)
[]

The for loop implicitly calls iter on the thing you are try to iterate over. By convention, all iterators are also iterable: an iterator's __iter__ should return self.

chepner
  • 497,756
  • 71
  • 530
  • 681