Q:

QuickSort in Python - explain the behavior of the implementation using list comprehension

I have a function called quickSort() that does just that. I am trying to understand the behavior of the 'smaller' and 'larger' lists (see below). Specifically, how does Python deal with memory when using recursion within a function? Each time the function is called, do the 'smaller' and 'larger' lists get overwritten (I'm assuming this happens...)? If so, where does the extra memory get released, as each function execution the lists will get smaller... 
def quickSort(lst):
   if len(lst) <= 1: 
      return lst
   smaller = [x for x in lst[1:] if x < lst[0]]
   larger = [x for x in lst[1:] if x >= lst[0]]
   return quickSort(smaller) + [lst[0]] + quickSort(larger)

What exactly happens with the two lists that are created, and if there is any benefit in using an in place sort in this scenario. 
Disclaimer: I am a novice at Python and algorithms in general, detailed explanations will be greatly appreciated. Thanks in advance. 
EDIT:
Here is the question rephrased:  
Starting with the initial list, [8,5,2,9,1,7,3,4,6]
quickSort #1 produces 3 lists: [5,2,1,7,3,4,6] , [8] , [9]
quickSort #2 produces 3 lists: [2,1,3,4] , [5] , [6,7] (plus [8] , [9])
quickSort #3 produces 5 lists: [1] , [2] , [3,4] and [6] , [7] (plus [8] , [9])
quickSort #4 produces 1 list: [1] , [2] , [3] , [4] , [5] , [6] , [7] , [8] ,[9] 
They are all concatenated in the process. What I am wondering is whether the lists [8,5,2,9,1,7,3,4,6] , [5,2,1,7,3,4,6] , [8] and so on are stored until the program exits. (The implementation above might not be correct, I just want to illustrate my point). 

A:

Quick sort is O(nlogn), it continuously cuts the problem into halves as you will see is what this problem does. 
Assuming a list x and calling quickSort(x)
x = [6,12,4,5,2,5,14,23,1,5]
quickSort(x)

This is a recursive function, from within itself it will call the function again. However, each call of the function has its own stack, it does not have access to variables outside its scope.
Ok so on the initial call of this function, smaller and larger will store lists associated with the values smaller than, and larger than, the first value in the list.
smaller = [4, 5, 2, 5, 1, 5]
larger = [12, 14, 23]

This split is done through list comprehension. We go through each value in the list except the first value. If the current value being evaluated is less than the first value in the list, then we will add it to the smaller list. We then do the same for the larger list.
Now the return function is
return quickSort(smaller) + [6] + quickSort(larger)

Let's do the smaller side first.
quickSort([4, 5, 2, 5, 1, 5])

lst[0] = 4
smaller = [2, 1]
larger = [5, 5, 5]

return quickSort(smaller) + [4] + quickSort(larger)

So this process continues until we reach a point where len(lst)<=1 and the recursion unravels backwards. Imagine a new branch of a tree extending each time the function is called. When the function finally returns the values propagate back up the tree. The end result is a sorted array.

[1, 2, 4, 5, 5, 5, 6, 12, 14, 23]

