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'>
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With