I see a article about the immutable object.
It says when:
variable = immutable
As assign the immutable to a variable.
for example
a = b # b is a immutable
It says in this case a
refers to a copy of b
, not reference to b
.
If b is mutable
, the a
wiil be a reference to b
so:
a = 10
b = a
a =20
print (b) #b still is 10
but in this case:
a = 10
b = 10
a is b # return True
print id(10)
print id(a)
print id(b) # id(a) == id(b) == id(10)
if a
is the copy of 10
, and b
is also the copy of 10
, why id(a) == id(b) == id(10)?
3 Answers 3
"Simple" immutable literals (and in particular, integers between -1 and 255) are interned, which means that even when bound to different names, they will still be the same object.
>>> a = 'foo'
>>> b = 'foo'
>>> a is b
True
-
This doesn't explain the entire first two thirds of his post, only the last third.agf– agf04/14/2012 04:50:00Commented Apr 14, 2012 at 4:50
-
@agf: The last one-third is the part that has the question.Ignacio Vazquez-Abrams– Ignacio Vazquez-Abrams04/14/2012 04:50:32Commented Apr 14, 2012 at 4:50
-
It's still important to point out that the conclusion he draws from the article he read is incorrect.agf– agf04/14/2012 04:51:35Commented Apr 14, 2012 at 4:51
-
I don't disagree that the wording is vague.Ignacio Vazquez-Abrams– Ignacio Vazquez-Abrams04/14/2012 04:52:32Commented Apr 14, 2012 at 4:52
While that article may be correct for some languages, it's wrong for Python.
When you do any normal assignment in Python:
some_name = some_name_or_object
You aren't making a copy of anything. You're just pointing the name at the object on the right side of the assignment.
Mutability is irrelevant.
More specifically, the reason:
a = 10
b = 10
a is b
is True
, is that 10
is interned -- meaning Python keeps one 10
in memory, and anything that is set to 10
points to that same 10
.
If you do
a = object()
b = object()
a is b
You'll get False
, but
a = object()
b = a
a is b
will still be True
.
-
2Python tries to intern
int
values, but does not always succeed. Trya = 1000
andb = 999
followed byb += 1
. When I tried it just now,a
andb
were each bound to a differentint
object with value 1000. I think the interning will always succeed for the values 0 and 1, though.steveha– steveha04/14/2012 05:30:56Commented Apr 14, 2012 at 5:30 -
this case:
lst = [0, 1, 2] * 2
, the list [0, 1, 2] is mutable, and I changelst[0][0] = 5
, the lst[1][0] will also change to 5, why?Tanky Woo– Tanky Woo04/14/2012 05:31:27Commented Apr 14, 2012 at 5:31 -
1@steveha It's not succeed or fail, it's -1 to 255, as Ignacio mentioned in his answer.agf– agf04/14/2012 05:32:13Commented Apr 14, 2012 at 5:32
-
@TankyWoo I assume you mean
[[0, 1, 2]] * 2
. Because you get a new list that has the same item in it twice, so changing it in either position makes the change show up in both positions. Python hasn't made a copy of the inner list, just pointed both index0
and index1
at it.agf– agf04/14/2012 05:34:44Commented Apr 14, 2012 at 5:34 -
@TankyWoo, the repetition of the list gives you two references to the same list. Try
id(lst[0])
andid(lst[1])
.steveha– steveha04/14/2012 05:34:59Commented Apr 14, 2012 at 5:34
Because interning has already been explained, I'll only address the mutable/immutable stuff:
As assign the immutable to a variable.
When talking about what is actually happening, I wouldn't choose this wording.
We have objects (stuff that lives in memory) and means to access those objects: names (or variables), these are "bound" to an object in reference. (You could say the point to the objects)
The names/variables are independent of each other, they can happen to be bound to the same object, or to different ones. Relocating one such variable doesn't affect any others.
There is no such thing as passing by value or passing by reference. In Python, you always pass/assign "by object". When assigning or passing a variable to a function, Python never creates a copy, it always passes/assigns the very same object you already have.
Now, when you try to modify an immutable object, what happens? As already said, the object is immutable, so what happens instead is the following: Python creates a modified copy.
As for your example:
a = 10
b = a
a =20
print (b) #b still is 10
This is not related to mutability. On the first line, you bind the int object with the value 10
to the name a
. On the second line, you bind the object referred to by a
to the name b
.
On the third line, you bind the int object with the value 20
to the name a
, that does not change what the name b
is bound to!
It says in this case a refers to a copy of b, not reference to b. If b is mutable, the a wiil be a reference to b
As already mentioned before, there is no such thing as references in Python. Names in Python are bound to objects. Different names (or variables) can be bound to the very same object, but there is no connection between the different names themselves. When you modify things, you modify objects, that's why all other names that are bound to that object "see the changes", well they're bound to the same object that you've modified, right?
If you bind a name to a different object, that's just what happens. There's no magic done to the other names, they stay just the way they are.
As for the example with lists:
In [1]: smalllist = [0, 1, 2]
In [2]: biglist = [smalllist]
In [3]: biglist
Out[3]: [[0, 1, 2]]
Instead of In[1] and In[2], I might have written:
In [1]: biglist = [[0, 1, 2]]
In [2]: smalllist = biglist[0]
This is equivalent.
The important thing to see here, is that biglist is a list with one item. This one item is, of course, an object. The fact that it is a list does not conjure up some magic, it's just a simple object that happens to be a list, that we have attached to the name smalllist
.
So, accessing biglist[i] is exactly the same as accessing smalllist, because they are the same object. We never made a copy, we passed the object.
In [14]: smalllist is biglist[0]
Out[14]: True
Because lists are mutable, we can change smallist, and see the change reflected in biglist. Why? Because we actually modified the object referred to by smallist. We still have the same object (apart from the fact that it's changed). But biglist will "see" that change because as its first item, it references that very same object.
In [4]: smalllist[0] = 3
In [5]: biglist
Out[5]: [[3, 1, 2]]
The same is true when we "double" the list:
In [11]: biglist *= 2
In [12]: biglist
Out[12]: [[0, 1, 2], [0, 1, 2]]
What happens is this: We have a list: [object1, object2, object3] (this is a general example) What we get is: [object1, object2, object3, object1, object2, object3]: It will just insert (i.e. modify "biglist") all of the items at the end of the list. Again, we insert objects, we do not magically create copies.
So when we now change an item inside the first item of biglist:
In [20]: biglist[0][0]=3
In [21]: biglist
Out[21]: [[3, 1, 2], [3, 1, 2]]
We could also just have changed smalllist
, because for all intents and purposes, biglist
could be represented as: [smalllist, smalllist]
-- it contains the very same object twice.
Explore related questions
See similar questions with these tags.
some_name[some_item]
on the left hand side of an=
) and pointing a name at a new object (by having justsome_name
on the left hand side of an=
). So if you haveinner = [0]
andouter = [inner, inner]
, if you doouter[0] = 1
you don't change inner, andouter
becomes[1, [0]]
. So even thoughinner
is mutable, you don't change it if you don't access a location in it by doingouter[0][0]
for example, where the second[0]
points insideinner
.