I'm trying to recursively iterate through all my nodes, however I get an infinite loop.
class Dictionary:
# STARTS CLASS NODE ################################################
class Node:
def __init__(self, key, value):
self.key = key
self.value = value
self.nextNode = None
def insert(self, key, value):
if self.nextNode is None or key < self.nextNode.key:
new = Dictionary.Node(key, value)
new.nextNode = self.nextNode
self.nextNode = new
elif key > self.nextNode.key:
self.nextNode.insert(key, value)
else:
pass
def __iter__(self):
if self.nextNode is None:
return self
else:
return self.__next__().__iter__()
def __next__(self):
return self.nextNode
def __str__(self):
return f'{self.key} : {self.value}'
# ENDS CLASS NODE ################################################
def __init__(self):
self.__head = None
def insert(self, key, value):
if self.__head is None or key < self.__head.key:
new = self.Node(key, value)
new.nextNode = self.__head
self.__head = new
elif key > self.__head.key:
self.__head.insert(key, value)
else:
pass
def __iter__(self):
return self.__head
def __str__(self):
return str(self.__head)
d = Dictionary()
d.insert(2, 2)
d.insert(3, 3)
d.insert(4, 4)
d.insert(5, 5)
When I do:
p = iter(d)
print(p)
print(next(p))
print(next(next(p))
it works, but when I do
for i in p:
print(i)
I get an infinite loop that prints 3s. It doesn't even jump nodes.
Isn't a for loop just the same thing as doing iter() and then using next() a bunch of times until I hit a condition (None)? Shouldn't I be getting the same thing for these? What am I doing wrong?
Your test code:
p = iter(d)
print(p)
print(next(p))
print(next(next(p)))
is not what happens in a for-loop.
That would be more like this:
it = iter(d)
print(next(it))
print(next(it))
...
and using your class, this would just give you the same element over and over again.
An iterator is an object that you call next
on repeatedly and it gives you a sequence of elements, until it raises an exception to signal that it is finished. Your __next__
implementation just returns self.nextNode
each time it is called. It won't ever raise an exception, so there's no signal that the iteration is finished.
If you want to write an iterator explicitly, you would need to create and update an object that keeps track of how far you had got through the iteration, which could be something like this:
class NodeIter:
def __init__(self, start):
self.cur = start
def __iter__(self):
return self
def __next__(self):
if self.cur is None:
raise StopIteration()
x = self.cur
self.cur = x.nextNode
return x
And then in your Dictionary you would have:
def __iter__(self):
return NodeIter(self.__head)
Alternatively, here is a quick way to write __iter__
that would go through all the nodes:
def __iter__(self):
cur = self.__head
while cur is not None:
yield cur
cur = cur.nextNode
This is a generator function, which is an easy way to generate a sequence using yield statements.