Reputation: 1471
Consider the following instance behavior in Python.
def change(elements):
elements[0] = 888
elements = [-3, -1, -2, -3, -4]
print(elements[0])
numbers = [1, 4, 5]
print(numbers[0])
change(numbers)
print(numbers[0])
print(numbers)
The Python snippet below prints
1
-3,
888
[888,4,5]
Shouldn't it print
1,
-3,
-3,
[-3,-1,-2,-3,-4]
Why would an element in a list by successfully overwritten, but not the entire list object?
Upvotes: 5
Views: 169
Reputation: 307
Looking at ID's will make understand ...
def change(elements):
print('inner first elements ID ',id(elements))
elements[0] = 888
print('inner second elements ID ',id(elements))
elements = [-3, -1, -2, -3, -4]
print('inner third elements ID ',id(elements))
print('inner third numbers ID ',id(numbers))
numbers = [1, 4, 5]
print(numbers[0])
print('outer numbers ID ',id(numbers))
change(numbers)
print('c ',numbers[0])
print('d', numbers)
Upvotes: 0
Reputation: 9987
That is a classic Python variable naming reference confusion. What I really like to to do to understand that though is print a reference to see what is going on.
def change(elements):
elements[0] = 888
print("ID of elements is: %d",id(elements))
elements = [-3, -1, -2, -3, -4]
print("ID of elements is: %d",id(elements))
print(elements[0])
numbers = [1, 4, 5]
print("ID of number is: %d",id(numbers))
print(numbers[0])
change(numbers)
print(numbers[0])
print(numbers)
>>>> ('ID of number is: %d', 140036366181584)
1
('ID of elements is: %d', 140036366181584)
('ID of elements is: %d', 140036366181944)
-3
888
[888, 4, 5]
The ID here represents an emplacement in memory. If you run the code the number might be different, but the behavior stays the same.
Basically, when you call
elements[0] = 888
You're actually mutating numbers
(same ID of 140036366181584
in my example).
But, when you call
elements = [-3, -1, -2, -3, -4]
You're creating a new list (different ID of 140036366181944
in my example) and re-assigning the local name elements
to it. Yo're simply assigning the name elements
to another object. It's not the same list anymore.
So, at this point all you did to numbers
is change its first index with the value 888
and this is what the output shows empirically.
Upvotes: 1
Reputation: 22041
No it shouldn't because in first line you override first value of parameter elements
and on the second you define new local variable for function.
Upvotes: 0
Reputation: 736
The list is passed as a reference to the function. So the list is shared between the global space and function. The first change modifies the list and that change is reflected in both spaces. But then you do and assignment to the list variable. That creates a new list in the function. The original list exists in the global space, but it no longer exists in the function. So all of the changes made to the list in the function from that point on are only visible within the function.
Another way of thinking about this instance is that the list is a type of container. The first line of the function changes what is in the container. The second line (the assignment) actually changes the container you are using. This is something that is true for lists but also for any object. This is why the solution given by @Chris_Rands in the comments works: it modifies what is in the container, it doesn't change the container.
Upvotes: 2
Reputation: 399
In change
function first you use elements
from outer scope, that was passed as the argument and is referenced - can be changed within function and those changed will affect the object even out of the local scope.
Then you create local instance of elements
, modify it and end the function. Since the elements
in global scope were changed earlier, you see "unexpected" result.
Check https://docs.python.org/3/reference/executionmodel.html for more details.
Upvotes: 0