input: from typing import Optional
  
  class Node:
      def __init__(self, data):
          self.data = data
          self.next: Optional[Node] = None
          self.prev: Optional[Node] = None
  
  class DoubleLinkedList:
      def __init__(self): 
          self.head: Optional[Node] = None
   
      def append(self, new_data): 
          new_node = Node(new_data) 
          if self.head is None:
              self.head =  new_node
          else: 
              curr_node = self.head
              while curr_node.next:
                  curr_node = curr_node.next
              curr_node.next = new_node
              new_node.prev = curr_node
   
      def prepend(self, new_data):
          new_node = Node(new_data) 
          if self.head is None: 
              self.head = new_node
              return
          new_node.next = self.head
          self.head.prev = new_node 
          self.head = new_node
  
      def reverse(self):
          curr_node = self.head
          while curr_node:
              temp = curr_node.next
              curr_node.next = curr_node.prev
              curr_node.prev = temp
              curr_node = curr_node.prev
          if temp:
              self.head = temp.prev
  
  # Test cases:
  # Test case 1:
  # Input: Create a DoubleLinkedList and append 1, 2, 3 and then prepend 0.
  # Output: head -> 0 <-> 1 <-> 2 <-> 3 <- tail
  # Test case 2:
  # Input: Reverse the linked list created above.
  # Output: head -> 3 <-> 2 <-> 1 <-> 0 <- tail
output:     
      def print_list(self):
          curr_node = self.head
          while curr_node:
              print(curr_node.data, end=" <-> " if curr_node.next else "\n")
              curr_node = curr_node.next
  
  # Test case 1:
  dll = DoubleLinkedList()
  dll.append(1)
  dll.append(2)
  dll.append(3)
  dll.prepend(0)
  dll.print_list()  # Output: head -> 0 <-> 1 <-> 2 <-> 3 <- tail
  
  # Test case 2:
  dll.reverse()
  dll.print_list()  # Output: head -> 3 <-> 2 <-> 1 <-> 0 <- tail
  