input: Write a function to implement a doubly linked list with the ability to append elements from the end, prepend elements from the beginning, and reverse the list. The function should include Node and DoubleLinkedList classes.
  
  class Node:
      def __init__(self, data):
          self.data = data
          self.next = None
          self.prev = None
  
  class DoubleLinkedList:
      def __init__(self): 
          self.head = 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 != None:
                  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
  
  assert DoubleLinkedList().append(1).append(2).append(3).prepend(0).reverse().head.data == 3
  assert DoubleLinkedList().append(5).append(10).prepend(0).reverse().head.data == 10
  assert DoubleLinkedList().append(7).append(8).prepend(6).reverse().head.data == 8
  assert DoubleLinkedList().append(15).prepend(10).reverse().head.data == 15
  assert DoubleLinkedList().append(20).prepend(15).reverse().head.data == 20
output: class Node:
      def __init__(self, data):
          self.data = data
          self.next = None
          self.prev = None
  
  class DoubleLinkedList:
      def __init__(self): 
          self.head = 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 != None:
                  curr_node = curr_node.next
              curr_node.next = new_node
              new_node.prev = curr_node
          return self
   
      def prepend(self, new_data):
          new_node = Node(new_data) 
          if self.head is None: 
              self.head = new_node
              return self
          new_node.next = self.head
          self.head.prev = new_node 
          self.head = new_node
          return self
  
      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
          return self