I created a simple Doubly Linked List, with an append method and a str() that is supposed to return the elements present in the list. Here is the code;
class Node:
def __init__(self,val):
self.next = None
self.prev = None
self.val = val
def __str__(self):
return self.val
class dll:
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def append(self,val):
new = Node(val)
if not self.head:
self.head = new
self.tail = new
else:
new.prev = self.tail
self.tail.next = new
self.tail = new
self.length += 1
def __str__(self):
curr = self.head
res = str()
if not self.head:
return("Linked list is empty")
while curr:
res += str(curr.val) + ' <-> '
curr = curr.next
if curr.next is not None:
res += ' <-> '
return res
ll = dll()
print(ll)
ll.append(10)
ll.append(30)
print(ll)
When I execute this, it returns "AttributeError: 'NoneType' object has no attribute 'next'"
I removed the condition
if curr.next is not None:
res += ' <-> '
And it works as expected, which is quite strange. I have created lists before and this has never happened to me. Am I doing something wrong? Thanks in advance!
The problem is in this section of your code:
curr = curr.next
if curr.next is not None:
res += ' <-> '
When curr
references the last node in the list, then after curr = curr.next
has been executed, curr
will be None
. But that makes curr.next
an invalid attribute access, and this produces the error you got.
What you really want is to check whether curr
was the last node, before moving forward. So change the order of your statements:
if curr.next is not None:
res += ' <-> '
curr = curr.next
This will solve the issue. Note that it makes sense to only change curr
at the very end of your loop body, so that everything else in the loop body gets to work with the same curr
.
I would suggest to change your __str__
method so that it doesn't have this repeated +=
, each time creating a new, longer, string. It is more pythonic to use join
for that purpose. I would also define __iter__
and then rely on that when defining __str__
:
def __iter__(self):
curr = self.head
while curr:
yield curr.val
curr = curr.next
def __str__(self):
return " <-> ".join(map(str, self)) if self.head else "(empty)"
With this in place you do things like this:
print(ll)
print(*ll)
print(list(ll))
print(sum(ll))