Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How an iterable object is iterated without next?

I've done a research over similar questions on this subject, but didn't find a duplicate.

It is stated that an object is iterable if it implements __iter__ protocol.

iterator.__iter__(): Return the iterator object itself. This is required to allow both containers and iterators to be used with the for and in statements.

iterator.__next__(): Return the next item from the container. If there are no further items, raise the StopIteration exception.

From my understanding this applies to all iterator objects. I've encountered a code that implements a binary-tree container. The container only has __iter__ and so does the node objects resides in it.

The __iter__ implementation of the Node objects returns a generator. It yields objects and seems to do all the logic, without an implementation of __next__.

How this code actually works? It seems to function just as a regular iterator, but this one has no __next__. Ofcourse if I manually do iter(obj) and then next(obj) it works. Here is the code snippet:

class BinaryCont(object):

    def __init__(self):
        self.root = None
        self.size = 0

    def __iter__(self):

        class EmptyIter():
            def next(self):
                raise StopIteration

        if self.root:
            return self.root.__iter__()
        return EmptyIter()

class Node(object):

    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

    def __iter__(self):
        if self.has_left_child():
            for child in self.left:
                yield child

        yield self.val

        if self.has_right_child():
            for child in self.right:
                yield child

An example of running code

bt = BinaryCont()
bt.insert(5)
bt.insert(3)
bt.insert(7)
for node in bt:
    print node

3
5
7

it = iter(bt)
type(it)
<type 'generator'>
like image 215
Chen A. Avatar asked Oct 02 '17 19:10

Chen A.


People also ask

How do you iterate over iterable?

We can iterate the elements of Java Iterable by obtaining the Iterator from it using the iterator() method. The methods used while traversing the collections using Iterator to perform the operations are: hasNext(): It returns false if we have reached the end of the collection, otherwise returns true.

Can we iterate an iterable using next method ()?

Iterating Through an IteratorWe use the next() function to manually iterate through all the items of an iterator. When we reach the end and there is no more data to be returned, it will raise the StopIteration Exception. Following is an example. A more elegant way of automatically iterating is by using the for loop.

Can you call next on an iterable?

To get the next value of the Iterable, call next() function on its iterator object. It will return the next value of the Iterable. Keep on calling this next() function to get all elements of iterable one by one. When iterator reaches the end of elements in iterable then it will throw StopIteration error.

What does __ ITER __ do in Python?

The __iter__() function returns an iterator for the given object (array, set, tuple, etc. or custom objects). It creates an object that can be accessed one element at a time using __next__() function, which generally comes in handy when dealing with loops.

What is an iterable object in Python?

An object is called iterable if we can get an iterator from it. Most of built-in containers in Python like: list, tuple, string etc. are iterables. The iter () function (which in turn calls the __iter__ () method) returns an iterator from them.

How to check if an object is iterable or not?

But if you need to check it explicitly, you can test for an iterable by hasattr (object_in_question, "__iter__") or hasattr (object_in_question, "__getitem__"). You need to check for both, because str s don't have an __iter__ method (at least not in Python 2, in Python 3 they do) and because generator objects don't have a __getitem__ method.

How to iterate through an object in Python?

An object is called iterable if we can get an iterator from it. Most built-in containers in Python like: list, tuple, string etc. are iterables. The iter () function (which in turn calls the __iter__ () method) returns an iterator from them. We use the next () function to manually iterate through all the items of an iterator.

How do you make an object iterable?

We can now apply this understanding to making objects iterable. The most important thing that is needed is defining the () method within the object, because this is what triggers the iterator.


2 Answers

Your __iter__ method is a generator function, because it uses yield in the function body. A generator function, when called, returns a generator object. It is that object that has a __next__ method.

Your Node is not an iterator itself. It is merely an iterable object; an iterable object returns a new iterator instance when you call it's __iter__ method, which is what happens here.

like image 188
Martijn Pieters Avatar answered Oct 12 '22 06:10

Martijn Pieters


A generator very much does have a __next__ method. You just don't implement it yourself. A "function" with a yield statement does not run your code. It returns an object that runs your code. That object has a __next__ method.

You may also want to note that there is one other mechanism for making an object iterable: providing __len__ and __getitem__ methods. In that case, iteration will occur over the indices from zero to len-1.

like image 29
Mad Physicist Avatar answered Oct 12 '22 07:10

Mad Physicist