Search code examples
pythonreturnparameter-passingpass-by-referencealias

Print statement before return statement is giving correct values but the function is returning Nonetype


I have an implementation of a function that sorts a stack. The function sortStack correctly sorts the stack but when I print the stack it seems to be modifying the initial parameter newStack2. Why does the return statement return None? Does it have something to do with pass by reference/aliasing?

class Stack():
    def __init__(self):
        self.stack = []

    def push(self,val):
        if len(self.stack)>=0:
            self.stack.append(val)
        else:
            return None

    def popOut(self):
        if len(self.stack) > 0:
            item = self.stack[-1]
            self.stack.pop()
            return item
        else:
            return None

    def peek(self):
        if self.isEmpty() == True:
            return None
        else:
            return self.stack[-1]

    def isEmpty(self):
        if len(self.stack) == 0:
            return True
        else:
            return False

def sortStack(stack1,stack2):
    if stack1.isEmpty() is False:
        if stack2.isEmpty() is True:
            item = stack1.popOut()
            stack2.push(item)
            sortStack(stack1,stack2)
        elif stack1.peek() < stack2.peek():
            item = stack1.popOut()
            stack2.push(item)
            sortStack(stack1,stack2)
        else:
            item = stack1.popOut()
            stack1.push(stack2.popOut())
            stack2.push(item)
            sortStack(stack1,stack2)
    else:
        stack1 = stack2
        return stack1

if __name__ == '__main__':
    newStack = Stack()
    newStack.push(5)
    newStack.push(4)
    newStack.push(6)
    newStack2 = Stack()

    print(sortStack(newStack,newStack2))
    print(newStack2.stack)

OUTPUT:

None
[6, 5, 4]

Solution

  • Insert a little basic tracing instrumentation:

    indent = "" def sortStack(stack1,stack2): global indent print(indent + "ENTER sortStack", stack1.stack, stack2.stack) indent += " "

    if stack1.isEmpty() is False:
        if stack2.isEmpty() is True:
            item = stack1.popOut()
            stack2.push(item)
            sortStack(stack1,stack2)
            print(indent + "LEAVE sortStack case A")
            indent = indent[2:]
        elif stack1.peek() < stack2.peek():
            item = stack1.popOut()
            stack2.push(item)
            sortStack(stack1,stack2)
            print(indent + "LEAVE sortStack case B")
            indent = indent[2:]
        else:
            item = stack1.popOut()
            stack1.push(stack2.popOut())
            stack2.push(item)
            sortStack(stack1,stack2)
            print(indent + "LEAVE sortStack case C")
            indent = indent[2:]
    else:
        print(indent + "      sortStack at bottom", stack2.stack)
        stack1 = stack2
        print(indent + "LEAVE sortStack at bottom", stack1.stack)
        indent = indent[2:]
        return stack1
    

    Output:

    ENTER sortStack [5, 4, 6] []
      ENTER sortStack [5, 4] [6]
        ENTER sortStack [5] [6, 4]
          ENTER sortStack [4] [6, 5]
            ENTER sortStack [] [6, 5, 4]
                    sortStack at bottom [6, 5, 4]
              LEAVE sortStack at bottom [6, 5, 4]
            LEAVE sortStack case B
          LEAVE sortStack case C
        LEAVE sortStack case B
      LEAVE sortStack case A
    returned None
    [6, 5, 4]
    

    There's your problem: only your innermost call returns any value; the rest of them throw away what that innermost call passes back up the line. This returns None.


    REPAIR

    Put the intended return value into a new variable; return that on any exit.

    indent = "" def sortStack(stack1,stack2): global indent print(indent + "ENTER sortStack", stack1.stack, stack2.stack) indent += " "

    if stack1.isEmpty() is False:
        if stack2.isEmpty() is True:
            item = stack1.popOut()
            stack2.push(item)
            result = sortStack(stack1,stack2)
            print(indent + "LEAVE sortStack case A")
            indent = indent[2:]
        elif stack1.peek() < stack2.peek():
            item = stack1.popOut()
            stack2.push(item)
            result = sortStack(stack1,stack2)
            print(indent + "LEAVE sortStack case B")
            indent = indent[2:]
        else:
            item = stack1.popOut()
            stack1.push(stack2.popOut())
            stack2.push(item)
            result = sortStack(stack1,stack2)
            print(indent + "LEAVE sortStack case C")
            indent = indent[2:]
    else:
        result = stack2
        print(indent + "LEAVE sortStack at bottom", result.stack)
        indent = indent[2:]
    
    return result
    

    OUTPUT:

    ENTER sortStack [5, 4, 6] []
      ENTER sortStack [5, 4] [6]
        ENTER sortStack [5] [6, 4]
          ENTER sortStack [4] [6, 5]
            ENTER sortStack [] [6, 5, 4]
              LEAVE sortStack at bottom [6, 5, 4]
            LEAVE sortStack case B
          LEAVE sortStack case C
        LEAVE sortStack case B
      LEAVE sortStack case A
    returned [6, 5, 4]
    [6, 5, 4]