4

I am trying to understand code that has a class to create a generator which is later iterated through with the next() built in fiction.

The class in question is this:

Class MyGen():
    def __init__(self):
    """ Define some instance attributes"""
        self.foo = 'bar'
        self.some_attribute = 0
    def __next__(self):
        if self.some_attribute < some_condition:
            new_value = self.argument1
            self.some_attribute += 1
            return new_value

In a global function, the returned object gets iterated through by the next() built in function. That is...

gen = Mygen()
next(gen) # Returns values

I don't understand how the class can be a generator without the __iter__() method. Is the __iter__() method necessary to produce a generator from a class? Everywhere I search it seems that __iter__() and __next__() are used together to create a generator from a class.

I'm fairly new to Python. This code sample was my best attempt at showing where the problem for me is, as the actual code does a lot more and would detract from the question and be too long to put here. I'm not experience enough to know how to shorten it more than this or more info is required.

Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
Nick Brady
  • 6,084
  • 1
  • 46
  • 71

2 Answers2

3

next(x) pretty much directly translates to x.__next__() in most cases.

So your __next__ method is called without gen being a "real" generator.

The call is valid, it's just a simple method call (makes no assumption nor checks about the object).

shx2
  • 61,779
  • 13
  • 130
  • 153
  • Thank you for your response! Does this mean the __iter__() method is required to make a generator through a class after all? When the x.__next__() method is called with that "fake" generator, will the values be stored in memory or are they created and lost similar to a generator? – Nick Brady Sep 29 '15 at 17:40
  • @NickBrady the full iterator protocol is required for e.g. `for _ in x:`; try that and see what happens. – jonrsharpe Sep 29 '15 at 17:42
  • @NickBrady: An aside: when you say *generator* I think you mean *iterator*. – Steven Rumbalski Sep 29 '15 at 17:42
  • Would it be more Pythonic to create a method that doesn't use the __next__() method as "it's just a simple method call." Thanks again all. – Nick Brady Sep 29 '15 at 17:52
1

The __iter__ method on an object should return an iterator for that object. It should be defined for any object which is iterable, and is called by the builtin iter() function, or by various statements (e.g. in the initialization step of a for i in obj: loop)

An iterator is just something with a __next__ method that returns the next item for the iterable or raises StopIteration when there are no items left. It is called by the builtin next() function and is called in various situations (e.g. just before the body of a for loop)

A generator is an iterable which is most likely not repeatable so often it is represented as an iterable which is also an iterator. So for most generators they define a __next__ method to yield the next element, and an __iter__ method that just returns self.

Chad S.
  • 6,252
  • 15
  • 25