Vinamra Bali
Vinamra Bali

Reputation: 111

Why big numbers show only two reference even when you define new variables?

When i use getrefcount method in sys module and try to count reference of certain big numbers (in this example 1000000) it shows two references. Now I know that these two references could be used by IDLE or python itself (as per the book) but when i introduce a variable a = 1000000 it should show 3 references but still shows 2. Any idea why this happens ?

>>> import sys
>>> sys.getrefcount(1000000)
2
>>> a = 1000000
>>> sys.getrefcount(1000000)
2

Upvotes: 2

Views: 123

Answers (3)

Alex Lopatin
Alex Lopatin

Reputation: 692

After the first call to sys.getrefcount(1000000) the literal 1000000 reference count is back to zero - nothing references it.

>>> import sys
>>> sys.getrefcount(1000000) 
2     # The literal 1000000 is created/referenced (1) and +getrefcount (1) = (2)
>>> a = 1000000 # The literal 1000000 is created/referenced (1)
>>> sys.getrefcount(1000000)
2     # The literal exists, so its references (1) and from getrefcount (1) = (2)

Here is the sample program with a random number (can be changed to any particular you like to test):

import sys
import random

number = random.randint(1, 1000000)
print(number, sys.getrefcount(number), "print got count too")
print(sys.getrefcount(number), "one less")
x = []
for i in range(100):
    x.append(number)

print(sys.getrefcount(number), "plus 100")

del x

print(sys.getrefcount(number), "back to original")
save = number
print(sys.getrefcount(number), "extra one")
del number
print(sys.getrefcount(save), "minus one one")
save_str = str(save)
del save
print(sys.getrefcount(int(save_str)), "only one")

Output:

3926 3 print got count too
2 one less
102 plus 100
2 back to original
3 extra one
2 minus one one
1 only one

The getrefcount is 1 when the number represented as string only at the end.

Upvotes: 1

Cloudomation
Cloudomation

Reputation: 1662

You are counting the references of the literal 1000000 twice.

>>> import sys
>>> sys.getrefcount(1000000)
3
>>> a = 1000000
>>> sys.getrefcount(a)
2
>>> b = a
>>> sys.getrefcount(a)
3

Edit

This really seems to work differently for small and larger numbers. Assigning small numbers actually references the same object as seen by id:

>>> import sys
>>> id(42)
8831008
>>> sys.getrefcount(42)
17
>>> a = 42
>>> id(a)
8831008
>>> id(42)
8831008
>>> sys.getrefcount(42)
18

For larger numbers the behaviour differs:

>>> import sys
>>> id(123456)
140049615070320
>>> sys.getrefcount(123456)
3
>>> a = 123456
>>> id(a)  # `a` references the literal from before
140049615070320
>>> id(123456)  # but a new literal of the same value is a different object
140049615070192
>>> sys.getrefcount(123456)
3

Also the behaviour differs across implementations of Python:

Python 3.6 on Mac:

Python 3.6.7 (v3.6.7:6ec5cf24b7, Oct 20 2018, 03:02:14) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> id(123456)
4452257552
>>> id(123456)
4452257552
>>> id(123456)
4452257552
>>> id(123456)
4452257552
>>> id(123456)
4452257552
>>> id(123456)
4452257552  # the literal is always the same object
>>> a = 123456
>>> id(a)
4452257552  # `a` references the same object as the literal before
>>> id(123456)
4452257648  # but the literal now references a new object
>>> id(123456)
4452257648  # a second time
>>> id(123456)
4449747760  # but every third time it references a new object
>>> id(123456)
4449747760
>>> id(123456)
4452257584
>>> id(123456)
4452257584
>>> id(123456)
4449750704
>>> id(123456)
4449750704
>>> id(123456)
4452257648
>>> id(123456)
4452257648

Python 3.7 on Linux:

Python 3.6.7 (default, Oct 22 2018, 11:32:17) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> id(123456)
140385586909904
>>> id(123456)
140385586909904
>>> id(123456)
140385586909904
>>> id(123456)
140385586909904
>>> id(123456)
140385586909904
>>> id(123456)
140385586909904
>>> a = 123456
>>> id(a)  # `a` references the same object as the literal before
140385586909904
>>> id(123456)  # the literal references a new object
140385586910320
>>> id(123456)
140385586910320
>>> id(123456)
140385586910320
>>> id(123456)
140385586910320
>>> id(123456)
140385586910320
>>> id(123456)
140385586910320
>>> id(123456)
140385586910320
>>> id(123456)
140385586910320
>>> b = 123456
>>> id(b)  # until it is assigned to a variable
140385586910320
>>> id(123456)  # then the literal references another new object
140385586910224
>>> id(123456)
140385586910224
>>> id(123456)
140385586910224
>>> id(123456)
140385586910224
>>> id(123456)
140385586910224
>>> id(123456)
140385586910224

Ultimately this seems to be an implementation detail which your code should not rely upon.

Upvotes: 1

NPE
NPE

Reputation: 500377

You seem to be assuming that every time you have 1000000 in your code, that refers to the same object. That's not the case.

What you have in your code are three different, unrelated 1000000 objects:

In [1]: id(1000000)
Out[1]: 4328822600

In [2]: id(1000000)
Out[2]: 4328822504

If you try a small integer instead, those get interned (at least by my interpreter) and so refcounts do increase:

In [7]: sys.getrefcount(3)
Out[7]: 284

In [8]: a = 3

In [9]: sys.getrefcount(3)
Out[9]: 287

Upvotes: 1

Related Questions