2
x1 = 5
y1 = 5
x2 = 'Hello'
y2 = 'Hello'
x3 = [1,2,3]
y3 = [1,2,3]
print(x1 is y1)
print(x2 is y2)
print(x3 is y3)

Output

True
True
False

Why Python assigns a different id to y3, other than x3?

Here x3 and y3 are lists, but Python does the same with tuples and dictionaries too. I also want to know where else Python has the same behaviour of assigning new id's to variables having the same values and why so?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
user5319825
  • 491
  • 1
  • 6
  • 16
  • Bonus: `print(253 is 252+1)` and `print(258 is 257+1)` – MariusSiuram Feb 18 '16 at 10:21
  • BonusBonus: `print("%s%s" % ("Hello" * 100,"World" * 100) is "Hello" * 100 + "World" * 100)` – MariusSiuram Feb 18 '16 at 10:23
  • Conclusion: Use `is` for `is None`, but for nothing more unless you know what you are doing and why you are doing it. – MariusSiuram Feb 18 '16 at 10:24
  • 1
    [mutable vs immutable objects](https://en.wikibooks.org/wiki/Python_Programming/Data_Types#Mutable_vs_Immutable_Objects) – Pedru Feb 18 '16 at 10:47
  • See http://stackoverflow.com/questions/306313/is-operator-behaves-unexpectedly-with-integers basicaully what cpython does is that it saves all ints from 0 to NSMALLPOSINTS to optimize memory usage. Try for yourself ``[sys.getrefcount(x) for x in range(300)]``. – Visgean Skeloru Feb 18 '16 at 11:55
  • @Pedru note that the behaviour not only depends on mutable vs immutable (strings are immutable, but they behave "strange" like in my "BonusBonus"). So... it is not enough to know that. And most behaviour will be CPython-dependent behaviour. – MariusSiuram Feb 18 '16 at 13:25

2 Answers2

5

Because otherwise this would happen:

x3 = [1,2,3]
y3 = [1,2,3]

x3[0] = "foo"
x3[0] == y3[0] # Does NOT happen!

In fact,

x3[0] != y3[0]

which is a Good Thing™. If x3 and y3 would be identical, changing one would change the other, too. That's generally not expected.

See also when does Python allocate new memory for identical strings? why the behaviour is different for strings.

Also, use == if you want to compare values.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • You mean to say, if x3 and y3 had same id then x3[0]==y3[0] would be True even if x3[0]='foo' and y3[0]=1? – user5319825 Feb 18 '16 at 09:50
  • I agree with your answer, but your "In fact" is confusing me. What do you mean? – MariusSiuram Feb 18 '16 at 10:19
  • In fact, changing `x3[0]` does *not* change `y3[0]`, they are `!=`. They are *not* `==`. –  Feb 18 '16 at 10:26
  • Normally "being not `==`" is equivalent to "`!=`", so I still don't find it illustrative. Sorry, maybe I am nit-picking because I was trying to read between lines and I should have not... – MariusSiuram Feb 18 '16 at 13:29
3

Tichodroma put it very nicely. However if you want to have same id() for lists, dicts, etc (if you want to have different names for the same object perhaps) that have same value, you can do it this way:

>>> x3 = y3 = [1,2,3]
>>> print(x3 is y3)
True

In that case x3 and y3 are referencing the same list object in memory. So, if you change any one of them, the other is going to change.

>>> x3[1] = 10
>>> y3
[1, 10, 3]
>>> x3
[1, 10, 3]

Bonus:

If integer values are same, not always will they have same id. Take a look here.

The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object.

Test:

>>> n = 256
>>> m = 256
>>> n is m
True
>>> n = 257
>>> m = 257
>>> n is m
False
>>> 

One more interesting test (go figure!):

>>> 2**8 is 2**8
True
>>> 2**9 is 2**9
False

P.S.: I am running python 3.4. And the quotation from docs is for python 2.7 (I didn't find the equivalent for python 3.4). But still I am getting outputs like that in python 3.4 I am running. So the current implementation as said for python 2.7 seems still valid for python 3.4.

Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90