Here is print_list() again:

In [1]:
def print_list(L):
    '''Print the list L element-by-element, one element per line'''
    
    #Base case: do nothing for lists of length 0
    if len(L) == 0:
        return 
    
    print(L[0])
    print_list(L[1:])

Here is the call tree for print_list([1, 2, 3, 4]):

    [ ]         (prints nothing -- returns straight away)
     |
    [4]         (prints 4)
     | 
   [3,4]        (prints 3)
     |
  [2, 3, 4]     (prints 2)
     |
[1, 2, 3, 4]    (prints 1)


Note the order in which things happen: when the call print_list([2, 3, 4]) happens, first we print 2, and then we make the call print_list([3, 4]).

Let's contrast this with print_list_reverse():

In [2]:
def print_reverse_list(L):
    '''Pritn the list L element-by-element in reverse, one element per line'''
    
    if len(L) == 0:
        return
    
    print_reverse_list(L[1:])
    print(L[0])

The call tree looks identical to what's above, except the order in which things happen differs. For example, when the call to print_list_reverse([2, 3, 4]) happens, first a call to print_list_reverse([3, 4]) happens (resulting in 4 and 3 being printed), and then 2 is printed.