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.
elements[:] = [-3, -1, -2, -3, -4]would produce your expected output...elements = somelistis simple assignment and merely rebinds the local name to a different object, whereaselements[:] = somelistonly looks like assignment. It's really syntactic sugar for calling a mutating method on the existing object referred to be the nameelements.