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__
: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.
__iter__
__iter__
__next__
__next__
iter(obj)
next(obj)
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
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'>
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.