Function changes list values and not variable values in Python

Python variables contain pointers, or references, to objects. All values (even integers) are objects, and assignment changes the variable to point to a different object. It does not store a new value in the variable, it changes the variable to refer or point to a different object. For this reason many people say that Python doesn't have "variables," it has "names," and the = operation doesn't "assign a value to a variable," but rather "binds a name to an object."

In plusOne you are modifying (or "mutating") the contents of y but never change what y itself refers to. It stays pointing to the same list, the one you passed in to the function. The global variable y and the local variable y refer to the same list, so the changes are visible using either variable. Since you changed the contents of the object that was passed in, there is actually no reason to return y (in fact, returning None is what Python itself does for operations like this that modify a list "in place" -- values are returned by operations that create new objects rather than mutating existing ones).

In plusOne2 you are changing the local variable a to refer to a different integer object, 3. ("Binding the name a to the object 3.") The global variable a is not changed by this and continues to point to 2.

If you don't want to change a list passed in, make a copy of it and change that. Then your function should return the new list since it's one of those operations that creates a new object, and the new object will be lost if you don't return it. You can do this as the first line of the function: x = x[:] for example (as others have pointed out). Or, if it might be useful to have the function called either way, you can have the caller pass in x[:] if he wants a copy made.


Create a copy of the list. Using testList = inputList[:]. See the code

>>> def plusOne(y):
        newY = y[:]
        for x in range(len(newY)):
            newY[x] += 1
        return newY

>>> y = [1, 2, 3]
>>> print plusOne(y), y
[2, 3, 4] [1, 2, 3]

Or, you can create a new list in the function

>>> def plusOne(y):
        newList = []
        for elem in y:
            newList.append(elem+1)
        return newList

You can also use a comprehension as others have pointed out.

>>> def plusOne(y):
        return [elem+1 for elem in y]

You can pass a copy of your list, using slice notation:

print plusOne(y[:]), y

Or the better way would be to create the copy of list in the function itself, so that the caller don't have to worry about the possible modification:

def plusOne(y):
    y_copy = y[:]

and work on y_copy instead.


Or as pointed out by @abarnet in comments, you can modify the function to use list comprehension, which will create a new list altogether:

return [x + 1 for x in y]