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'>