-->

Two variables in Python have same id, but not list

2020-01-23 06:55发布

问题:

Two variables in Python have the same id:

a = 10
b = 10
a is b
>>> True

If I take two lists:

a = [1, 2, 3]
b = [1, 2, 3]
a is b
>>> False

according to this link Senderle answered that immutable object references have the same id and mutable objects like lists have different ids.

So now according to his answer, tuples should have the same ids - meaning:

a = (1, 2, 3)
b = (1, 2, 3)
a is b
>>> False

Ideally, as tuples are not mutable, it should return True, but it is returning False!

What is the explanation?

回答1:

Immutable objects don't have the same id, and as a mater of fact this is not true for any type of objects that you define separately. Generally speaking, every time you define an object in Python, you'll create a new object with a new identity.

However, for the sake of optimization (mostly) there are some exceptions for small integers (between -5 and 256) and small strings (interned strings, with a special length (usually less than 20 character)) which are singletons and have same id (actually one object with multiple pointer). You can check this fact like following:

>>> 30 is 20 + 10
True
>>> 
>>> 300 is 200 + 100
False
>>> 'aa' * 2 is 'a' * 4
True
>>> 'aa' * 20 is 'a' * 40
False

And for a custom object:

>>> class A:
...    pass
... 
>>> A() is A() # Every time you create an instance you'll have a new instance with new identity
False

Also note that the is operator will check the object's identity, not the value. If you want to check the value you should use ==:

>>> 300 == 3*100
True

And since there is no such rule for tuples (other types) if you define the two same tuples in any size they'll get their own ids:

>>> a = (1,)
>>> b = (1,)
>>>
>>> a is b
False

And note that the fact of singleton integers and interned strings is true even when you define them within mutable and immutable objects:

>>> a = (100, 700, 400)
>>>
>>> b = (100, 700, 400)
>>>
>>> a[0] is b[0]
True
>>> a[1] is b[1]
False


回答2:

Immutable != same object.*

An immutable object is simply an object whose state cannot be altered; and that is all. When a new object is created, a new address will be assigned to it. As such, checking if the addresses are equal with is will return False.

The fact that 1 is 1 or "a" is "a" returns True is due to integer caching and string interning performed by Python so do not let it confuse you; it is not related with the objects in question being mutable/immutable.


*Empty immutable objects do refer to the same object and their isness does return true, this is a special implementation specific case, though.



回答3:

Take a look at this code:

>>> a = (1, 2, 3)
>>> b = (1, 2, 3)
>>> c = a
>>> id(a)
178153080L
>>> id(b)
178098040L
>>> id(c)
178153080L

In order to figure out why a is c is evaluated as True whereas a is b yields False I strongly recommend you to run step-by-step the snippet above in the Online Python Tutor. The graphical representation of the objects in memory will provide you with a deeper insight into this issue (I'm attaching a screenshot).



回答4:

Check below code.. tupils a and b are retaining their older references(ID) back when we have assigned their older values back. (BUT, THIS WILL NOT BE THE CASE WITH LISTS AS THEY ARE MUTABLE)

Initially a and b have same values ( (1,2) ), but they have difference IDs. After alteration to their values, when we reassign value (1,2) to a and b, they are now referencing to THEIR OWN same IDs (88264264 and 88283400 respectively).

>>> a = (1,2)
>>> b = (1,2)
>>> a , b
((1, 2), (1, 2))
>>> id(a)
88264264
>>> id(b)
88283400
>>> a = (3,4)
>>> b = (3,4)
>>> id(a)
88280008
>>> id(b)
88264328
>>> a = (1,2)
>>> b = (1,2)
>>> id(a)
88264264
>>> id(b)
88283400
>>> a , b
((1, 2), (1, 2))
>>> id(a) , id(b)
(88264264, 88283400)
>>> 

**Check the link Why don't tuples get the same ID when assigned the same values? also after reading this. Another case also been discussed here.