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

Author: Reditadata, 2017-06-01

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)
 1
Author: diralik, 2017-06-01 10:35:36

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()
 0
Author: Igor Lavrynenko, 2017-06-01 10:46:09