Python list doesn't reflect variable change
Python variables hold references to values. Thus, when you define the palin
list, you pass in the value referenced by polly
, not the variable itself.
You should imagine values as balloons, with variables being threads tied to those balloons. "alive"
is a balloon, polly
is just a thread to that balloon, and the palin
list has a different thread tied to that same balloon. In python, a list is simply a series of threads, all numbered starting at 0.
What you do next is tie the polly
string to a new balloon "dead"
, but the list is still holding on to the old thread tied to the "alive"
balloon.
You can replace that thread to "alive"
held by the list by reassigning the list by index to refer to each thread; in your example that's thread 1
:
>>> palin[1] = polly
>>> palin
['parrot', 'dead']
Here I simply tied the palin[1]
thread to the same thing polly
is tied to, whatever that might be.
Note that any collection in python, such as dict
, set
, tuple
, etc. are simply collections of threads too. Some of these can have their threads swapped out for different threads, such as lists and dicts, and that's what makes something in python "mutable".
Strings on the other hand, are not mutable. Once you define a string like "dead"
or "alive"
, it's one balloon. You can tie it down with a thread (a variable, a list, or whatever), but you cannot replace letters inside of it. You can only tie that thread to a completely new string.
Most things in python can act like balloons. Integers, strings, lists, functions, instances, classes, all can be tied down to a variable, or tied into a container.
You may want to read Ned Batchelder's treatise on Python names too.
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.
Python: why does my list change when I'm not actually changing it?
That's because both list
and list2
are referring to the same list after you did the assignment list2=list
.
Try this to see if they are referring to the same objects or different:
id(list)
id(list2)
An example:
>>> list = [1, 2, 3, 4, 5]
>>> list2 = list
>>> id(list)
140496700844944
>>> id(list2)
140496700844944
>>> list.remove(3)
>>> list
[1, 2, 4, 5]
>>> list2
[1, 2, 4, 5]
If you really want to create a duplicate copy of list
such that list2
doesn't refer to the original list but a copy of the list, use the slice operator:
list2 = list[:]
An example:
>>> list
[1, 2, 4, 5]
>>> list2
[1, 2, 4, 5]
>>> list = [1, 2, 3, 4, 5]
>>> list2 = list[:]
>>> id(list)
140496701034792
>>> id(list2)
140496701034864
>>> list.remove(3)
>>> list
[1, 2, 4, 5]
>>> list2
[1, 2, 3, 4, 5]
Also, don't use list
as a variable name, because originally, list
refers to the type list, but by defining your own list
variable, you are hiding the original list
that refers to the type list. Example:
>>> list
<type 'list'>
>>> type(list)
<type 'type'>
>>> list = [1, 2, 3, 4, 5]
>>> list
[1, 2, 3, 4, 5]
>>> type(list)
<type 'list'>
Changing one list unexpectedly changes another, too
Why does v change at all?
vec
and v
are both references.
When coding vec = v
you assign v
address to vec
.
Therefore changing data in v
will also "change" vec
.
If you want to have two different arrays use:
vec = list(v)
python: changes to my copy variable affect the original variable
That is because in python setting a variable actually sets a reference to the variable. Almost every person learning python encounters this at some point. The solution is simply to copy the list:
copy_list = org_list[:]
Related Topics
How to Use Subprocess Popen Python
Way to Change Google Chrome User Agent in Selenium
Add Leading Zeros to Strings in Pandas Dataframe
Lost Connection to MySQL Server During Query
Python Date String to Date Object
Sort List of Lists Ascending and Then Descending
Negative Integer Division Surprising Result
Python Ctypes - Loading Dll Throws Oserror: [Winerror 193] %1 Is Not a Valid Win32 Application
In Matplotlib, What Does the Argument Mean in Fig.Add_Subplot(111)
What's the How to Install Pip, Virtualenv, and Distribute for Python
What's the Difference Between Select_Related and Prefetch_Related in Django Orm
How to Search Directories and Find Files That Match Regex
Pandas: Rolling Mean by Time Interval
How to Automatically Install Required Packages from a Python Script as Necessary