Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does this class implement the "__iter__" method without implementing "next"?

Tags:

I have the following code in django.template:

class Template(object):
    def __init__(self, template_string, origin=None, name='<Unknown Template>'):
        try:
            template_string = smart_unicode(template_string)
        except UnicodeDecodeError:
            raise TemplateEncodingError("Templates can only be constructed from unicode or UTF-8 strings.")
        if settings.TEMPLATE_DEBUG and origin is None:
            origin = StringOrigin(template_string)
        self.nodelist = compile_string(template_string, origin)
        self.name = name

    def __iter__(self):
        for node in self.nodelist:
            for subnode in node:
                yield subnode

    def render(self, context):
        "Display stage -- can be called many times"
        return self.nodelist.render(context)

The part I am confused about is below. How does this __iter__ method work? I can't find any corresponding next method.

def __iter__(self):
        for node in self.nodelist:
            for subnode in node:
                yield subnode

This is the only way that I know how to implement __iter__:

class a(object):
    def __init__(self,x=10):
        self.x = x
    def __iter__(self):
        return self
    def next(self):
        if self.x > 0:
            self.x-=1
            return self.x
        else:
            raise StopIteration
 ainst = a()
 for item in aisnt:
     print item

In your answers, try to use code examples rather than text, because my English is not very good.

like image 633
zjm1126 Avatar asked Dec 25 '09 02:12

zjm1126


2 Answers

From the docs:

If a container object’s __iter__() method is implemented as a generator, it will automatically return an iterator object (technically, a generator object) supplying the __iter__() and __next__() methods.

Here is your provided example using a generator:

class A():     def __init__(self, x=10):         self.x = x     def __iter__(self):         for i in reversed(range(self.x)):             yield i  a = A() for item in a:     print(item) 
like image 89
Mark Peters Avatar answered Oct 06 '22 01:10

Mark Peters


That __iter__method returns a python generator (see the documentation), as it uses the yield keyword. The generator will provide the next() method automatically; quoting the documentation:

What makes generators so compact is that the __iter__() and next() methods are created automatically.

EDIT:

Generators are really useful. If you are not familiar with them, I suggest you readup on them, and play around with some test code.

Here is some more info on iterators and generators from StackOverflow.

like image 27
catchmeifyoutry Avatar answered Oct 06 '22 00:10

catchmeifyoutry