Reputation: 807
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,
Upvotes: 0
Views: 85
Reputation: 350760
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]
Upvotes: 4
Reputation: 19143
Your TA is right, the return is redundant because of what in python is called aliasing.
Basically, in your function, p_list
is a reference (NOT a copy) to whatever list you pass in when you call the function. Since you use pop
, which mutates the list in-place when extracting an element, p_list
will be modified and this modification will be visible outside the function:
drop_zeros(q) # from here, in the function, p_list is q (as in, exactly the same object)
print(q)
prints
[-2,1,0,0,1]
Upvotes: 0