from copy import copy

class LinkedList:
  def __init__(self,head:object=None, rest:'LinkedList'=None): 
    """Create a new LinkedList
    head - The first element of the linked list, 
           Not present if self will be the empty linked list.
    rest - The linked list that contains the elements after head. 
           Not present if self will be the empty linked list.""" 
    self.empty = (head is None) and (rest is None)
    if not self.empty:
      self.head = head
      if rest is None:
        self.rest = LinkedList()
      else:
        self.rest = rest
        
  def prepend(self,newhead:object):
    """Add head to the front of self"""
    selfcopy = copy(self)
    self.head = newhead
    self.rest = selfcopy
    self.empty = False

  def delete_head(self):
    """Delete the head (first element) of self"""
    if self.empty:
      raise Exception("The empty list has no head (first element), so "
                      "calling delete_head on it is an error.")
    elif not self.rest.empty:
      self.head, self.rest = self.rest.head, self.rest.rest
    else:
      self.empty = True
      del(self.head)
      del(self.rest)      

      
  def __contains__(self,value:object) -> bool:
    """Return whether self contains value"""
    return (not self.empty and
            (self.head == value or value in self.rest))    

  def __repr__(self):
     if self.empty:
         return 'LinkedList()'
     else:
         return 'LinkedList({}, {})'.format(
             repr(self.head), repr(self.rest))   
      
  
def linked_list_from_seq(*args) -> LinkedList:
  if len(args) == 0:
    raise Exception("can't have an empty linked list")
  elif len(args) == 1:
    return LinkedList(args[0], None)
  else:
    return LinkedList(args[0], linked_list_from_seq(*args[1:]))


if __name__ == '__main__':
  l1 = linked_list_from_seq(1,2,3,4)
  l2 = LinkedList(1,
                  LinkedList(2,
                             LinkedList(3,
                                        LinkedList(4,None))))
  # we haven't implemented an __eq__ method, so this will
  # be false, since l1 and l2 are distinct objects in memory.
  print(l1 == l2)
  # but they are equivalent with respect to repr:
  print(repr(l1) == repr(l2))
  
  print(l1)
  l1.delete_first()
  print(l1)
  l1.prepend(0)
  print(l1)
  print(l1.rest.rest)
  l1.rest.rest.delete_first()
  print(l1)