Python-NameError (bidirectional linked list)
Am I implementing a bidirectional linked list correctly and, if so, how do I fix the error?
class Cell:
def __init__(self, value, name, prev, next):
self.value = value
self.name = name
self.prev = prev
self.next = next
E = Cell(5, "E", D, None)
D = Cell(4, "D", C, E)
C = Cell(3, "C", B, D)
B = Cell(2, "B", A, C)
A = Cell(1, "A", None, B)
NameError: name 'D' is not defined
2 answers
You are on the right track, but if the list constructor accepts both the previous and next vertices, then a cyclic dependency will occur. A possible solution is to remove prev
and next
from the constructor and move their installation to a separate method:
class Cell:
def __init__(self, value, name):
self.value = value
self.name = name
def set_prev_and_next(self, prev, next):
self.prev = prev
self.next = next
A = Cell(1, 'A')
B = Cell(2, 'B')
C = Cell(3, 'C')
D = Cell(4, 'D')
E = Cell(5, 'E')
A.set_prev_and_next(E, B)
B.set_prev_and_next(A, C)
C.set_prev_and_next(B, D)
D.set_prev_and_next(C, E)
E.set_prev_and_next(D, A)
However, in this case, you will need to use the handles each time to ensure that the values of prev
and next
are consistent. For example, if you want to insert an item in the middle of the list, you will need to call the method set_prev_and_next
for three elements: the inserted one, the previous one, and the next one. A much better option would be to write a method like insert_after
, which will insert an element after some element and handle the consistency of the values of prev
and next
itself. For example, so:
class Cell:
def __init__(self, value, name):
self.value = value
self.name = name
self.prev = None
self.next = None
def insert_after(self, cell):
if self.next is None:
cell.prev = self
cell.next = self
self.prev = cell
self.next = cell
else:
cell.prev = self
cell.next = self.next
self.next = next
cell.next.prev = cell
A = Cell(1, 'A')
B = Cell(2, 'B')
C = Cell(3, 'C')
D = Cell(4, 'D')
E = Cell(5, 'E')
B.insert_after(A)
C.insert_after(B)
D.insert_after(C)
E.insert_after(D)
You will not be able to call the variable before it is defined, you need to change the order so that the interpreter knows where you are accessing, so it will not work
E = Cell(5, "E", D, None)
D = Cell(4, "D", C, E)
C = Cell(3, "C", B, D)
B = Cell(2, "B", A, C)
A = Cell(1, "A", None, B)
You can try to change the logic, I can make mistakes and I will be grateful for the edits of more experienced participants
class Constr(object):
def __init__(self, value, name, prev=None):
self.value = value
self.name = name
self.prev = prev
self.next = None
def add_next(self, obj):
self.next = obj
def show(self):
answer = dict(name=self.name, value=self.value, prev=self.prev, next=self.next)
return answer
class Contain(object):
def __init__(self):
self.all_obj = []
def update_obj(self, value, name):
if not self.all_obj:
new = Constr(value, name)
self.all_obj.append(new)
else:
update_obj = self.all_obj[-1]
new_obj = Constr(value, name, prev=update_obj)
update_obj.add_next(new_obj)
self.all_obj.append(new_obj)
return True
def get_list(self):
if self.all_obj:
return [i.show() or None for i in self.all_obj]
return []
test = Contain()
test.update_obj(1, 'hello')
test.update_obj(2, 'world')
test.update_obj(3, '!')
test.get_list()