6

Running:

a = 257
b = 257
print id(a) == id(b)

Results in:

same statement enter image description here

Same statement but opposite results. Why?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Abirdcfly
  • 326
  • 4
  • 13
  • 1
    Why are you comparing integers by ID? – jonrsharpe Apr 07 '16 at 11:32
  • 1
    see : http://stackoverflow.com/questions/3402679/identifying-objects-why-does-the-returned-value-from-id-change interpreter might not cache those number, because it does not know if you're going to reuse it – Hacketo Apr 07 '16 at 11:33
  • 2
    @Hacketo: That's different. This question is about two variables that are equivalent integers having the same id when run from a file, but different id's when run in the shell. – zondo Apr 07 '16 at 11:35
  • 1
    @jonrsharpe It is a special number. Values between -5 and 256 are preallocated. So I test 257 – Abirdcfly Apr 07 '16 at 11:38
  • One point is that python has some kind of small memory of range of integer numbers, and they always will have same id. But in this case, it's really something weird – Sergius Apr 07 '16 at 11:38
  • @Abirdcfly I know that, but why are you doing it *at all?* This is just implementation detail. – jonrsharpe Apr 07 '16 at 11:39
  • If a and b are declared together then the output is True. >>> a, b = 257, 257 >>> id(a) == id(b) True – Ajit Vaze Apr 07 '16 at 11:41
  • @jonrsharpe Because I am reading the source code and I just try. – Abirdcfly Apr 07 '16 at 11:43
  • [>>>257 is 257](http://stackoverflow.com/questions/306313/is-operator-behaves-unexpectedly-with-integers)In fact,I find this question's answer may be same to this question. – Abirdcfly Apr 07 '16 at 14:41

1 Answers1

10

The code in test.py is parsed together which is more optimizable than the code parsed as separate statements in the interpreter

When you put it in a test.py and run it as a whole, the byte code compiler has a better chance of analyzing the usage of literals and optimizing them. (Hence you get a and b pointing to the same place)

As opposed to when you run the separate statements (parsed separately) in the interpreter (where I think it only optimizes up to 256 but not 257 via preallocation)

Play with this in the interpreter to see the effect of separate statements:

>>> a, b = 257, 257      # or if you prefer: a = 257; b = 257
>>> print a is b
True

>>> a = 257
>>> b = 257
>>> print a is b
False

Defining a function in the interperter also gives it a change to analyze and optimize the used literals

>>> def test():
...     a = 257
...     b = 257
...     print a is b
... 
>>> test()
True

This optimization is not limited to integers only, works e.g. for floats too (floats are not subject to a cache like integers in the [-5, 256] range are)

>>> def test():
...     pi = 3.14
...     x = 3.14
...     return x is pi
... 
>>> test()
True

# As opposed to separate statements:
>>> pi = 3.14
>>> x = 3.14
>>> x is pi
False

Looking at the byte code to see that it indeed reuses the same constant

>>> dis.dis(test)
  2           0 LOAD_CONST               1 (3.14)
              3 STORE_FAST               0 (pi)

  3           6 LOAD_CONST               1 (3.14) <-- Same constant 1 reused
              9 STORE_FAST               1 (x)

  4          12 LOAD_FAST                1 (x)
             15 LOAD_FAST                0 (pi)
             18 COMPARE_OP               8 (is)
             21 RETURN_VALUE  
bakkal
  • 54,350
  • 12
  • 131
  • 107
  • From the comments, the OP knows that "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." from [the docs](https://docs.python.org/2/c-api/int.html#c.PyInt_FromLong). – PM 2Ring Apr 07 '16 at 11:45
  • I'm with you, but can we dig more ? :) – Abirdcfly Apr 07 '16 at 11:49