Search code examples
pythonlistobjectvariable-assignmentmutable

Does Python automatically update variables whose value is another object?


Before asking, I read the accepted answer to the question "How do I pass a variable by reference?" and documentation linked in that same answer: "How do I write a function with output parameters (call by reference)?"

I have a related question: Does Python automatically synchronize a variable whose value is a reference to another object? In other words, if I assign an object as the value of a variable, is the variable updated whenever the object is modified?

I have a specific problem where it appears that Python updates the value of a variable with an object as its value without any code explicitly triggering an update. I created a function that was supposed to be part of a solution to the ROT13 (rotate right 13 times) problem: shift an array to the right 13 times. Here is the function's code:

array = [0, 1, 2, 3, 4, 5]
print(array)
backup = array

#backup = [n for n in array]

for i in range( 1, (len(backup)) ):
    array[i] = backup[i - 1]

array[0] = backup[-1]
backup = array
print(array)

The output of that code is wrong: [0, 0, 0, 0, 0, 0] . However, when I replace line 3 (backup = array) with backup = [n for n in array], the answer is correct: [5, 0, 1, 2, 3, 4]

I inferred that whenever the for-loop executed, the value of backup was updated because its value is inherently a reference to the object array. It appears to me that when array[1] was assigned the value zero, backup[1] was also assigned zero instead of holding the value 1. Because of that, the for-loop simply assigned the value zero to every other variable in backup thru array.

If I instead assigned backup to a list object distinct from array using backup = [n for n in array], modifying array would not modify backup.

What is the actual cause of this behavior?


Solution

  • In your example backup and array are both references to the same object. That is clear with this code example:

    >>> array=[1,2,3,4]
    >>> backup=array
    >>> id(array)
    4492535840
    >>> id(backup)
    4492535840
    

    So your code is equivalent to this:

    array = [0, 1, 2, 3, 4, 5]
    print(array)
    
    for i in range( 1, (len(array)) ):
        array[i] = array[i - 1]
    
    array[0] = array[-1]
    print(array)
    

    Does that help?