Search code examples
pythonlistreturn

What is common pratice with return statements in functions?


I'm having trouble with understanding when to use the return function. In the below function my intuition is that the return statement should be there to return the modified list, but my TA said is was redundant which I didn't quite understand why. Any clarification on when to correctly use return statement and on common practise would be highly appreciated.

p = [2,0,1]
q = [-2,1,0,0,1,0,0,0]
p1 = [0,0,0,0]

#Without return statement
def drop_zeros1(p_list):
    """drops zeros at end of list"""
    i = 0 
    while i < len(p_list):
            if p_list[-1]==0:
                p_list.pop(-1)
            else:
                break

#With return statement
def drop_zeros(p_list):
    """drops zeros at end of list"""
    i = 0 
    while i < len(p_list):
            if p_list[-1]==0:
                p_list.pop(-1)
            else:
                return p_list
                break

Also why the output is inconsistent when used on the list p1, it only removes the last 0 when it should remove all zeroes?

Many Thanks,


Solution

  • The convention is that functions either mutate the argument(s) given to it, or return the result, but then leave the arguments untouched.

    This is to prevent that a user of your function would do this:

    template = [1, 2, 0, 0]
    shorter = drop_zeros(template)
    print ("input was ", template, " and output was ", shorter)
    

    They would expect this output:

    input was [1, 2, 0, 0] and output was [1, 2]

    ... but be surprised to see:

    input was [1, 2] and output was [1, 2]

    So to avoid this, you would either:

    • not return the modified argument, but None. That way the above code would output ...and output was None, and the user would understand that the function is not designed to return the result.

    • return the result, but ensure that the argument retains its original content

    So in your case you could do:

    def drop_zeros(p_list):
        """drops zeroes at end of list, in-place"""
        while p_list and p_list[-1] == 0:
            p_list.pop()
    

    Note that the else can be better integrated into the while condition. No more need to do an explicit break. Also .pop() does not need -1 as argument: it is the default.

    If you prefer a function that returns the result, then the logic should be somewhat different:

    def drop_zeros(p_list):
        """returns a copy of the list without the ending zeroes"""
        for i in range(len(p_list)-1, -1, -1):
             if p_list[i] != 0:
                 return p_list[0:i+1]
        return []
    

    Now the code is designed to do:

    template = [1, 2, 0, 0]
    shorter = drop_zeros(template)
    print ("input was ", template, " and output was ", shorter)
    # input was [1, 2, 0, 0] and output was [1, 2]