Understanding how mutable variables behave across different scopes

Question:

Newbie to Python here. While practicing working with lists on Codingbat, I realized there are behaviors I don’t understand concerning lists and how mutable variables behave. Sample below is derived from a few Codingbat problems to frame my questions…

  1. In getManipulatedNewList(), newnums is destroyed because it goes out of scope (this is correct?), so that’s why bobo gets None that first time.

  2. I’m now assuming the only way to ensure I get an actual copy of a list is to create it outside a function–so deepcopying must happen outside the function that manipulates a list, within the same scope where the new list will be used. Correct?

  3. Then what is being passed in the last function below (whatIsThisDoing()–I’m obviously creating a new list with the 1st and last elements of parameter “nums”, which I then return immediately. Bobo gets assigned that new list successfully (otherwise arr[0] = 999 would have changed the 1st value in bobo as well).

Why does that work, but getManipulatedNewList() destroys newnums?

Is there any way to pass newnums the same way that anonymous list is returned, so it doesn’t get destroyed?

(Or what am I misunderstanding here, please 🙂

import copy

def getManipulatedNewList(nums):
    # Create new list
    newnums = copy.deepcopy(nums)

    # For example only; assume many, more complex list manipulations
    # occur here
    newnums = newnums.reverse()

    # Return the newly-created list reference (doesn't work.)
    return newnums


def manipulateList(nums):
    # For example only; assume many, more complex list modifs
    # occur here
    nums = nums.reverse()

    # Nothing to return


def whatIsThisDoing(nums):
    # This actually returns something!
    # Why, though? It's creating the new list in this function too.
    return [nums[0], nums[-1]]

if __name__ == '__main__':
    arr = [1,2,3]
    print(arr)
    print("---")

    bobo = getManipulatedNewList(arr)
    print(arr)  # Shouldn't be touched, as expected
    print(bobo) # newnums was destroyed so bobo is None
    print("---")

    # Is this the only good solution to working with mutable vars?
    bobo = copy.deepcopy(arr)
    manipulateList(bobo)
    print(bobo)

    # Why does this work?
    bobo = whatIsThisDoing(arr)
    print(bobo)
    print("---")

    arr[0] = 999
    print(bobo) # bobo[0] isn't changed, so it's not referencing arr[0]
Asked By: Gee

||

Answers:

No. The reason you get None is because that is what is returned from reverse; that method works in place. The issue has been nothing to do with scope, and the rest of your misunderstandings stem from that.

Answered By: Daniel Roseman