By using collections.deque or self implementation example below:

    #!/usr/bin/env python3
    
    class LinkedList():
        def __init__(self, data=None):
            self.head = None
    
            if data is not None:
                node = Node(data.pop(0))
                self.head = node
                for d in data:
                    node.next = Node(d)
                    node = node.next
    
        def add_tail(self, node):
            if self.head is None:
                self.head = node
                return self
    
            ln = None
            for n in self:
                ln = n
            ln.next = node
    
            return self
    
        def add_head(self, node):
            if self.head is None:
                self.head = node
                return self
    
            if node.next is not None:
                ln = node.next
                while ln.next is not None:
                    ln = ln.next
            else:
                ln = node
    
            ln.next = self.head
            self.head = node
    
        # def __next__(self) # NOTE dont need with yield, generator class does the __next__
    
        def __iter__(self):
            node = self.head
    
            while node is not None:
                yield node
                node = node.next
    
        def __str__(self):
            return str([n._d for n in self])
    
    
    class Node():
        def __init__(self, data):
            self._d = data
            self.next = None
    
    if __name__ == "__main__":
        ll = LinkedList([1, 2, 3])
        print(ll) # [1, 2, 3]
        n = Node(4)
        n.next = Node(5)
        ll.add_tail(n).add_tail(Node(6))
        print(ll) # [1, 2, 3, 4, 5, 6]
        n2 = Node(-1)
        n2.next = Node(0)
        ll.add_head(n2)
        ll.add_head(Node(-2))
        print(ll) # [-2, -1, 0, 1, 2, 3, 4, 5, 6]