I am using repl.it
for python3 -
Here is a sequence of assignments I did
x34=20
x34
=> 20
hex(id(x34))
=> '0x7fdb5d318960'
x34=30
hex(id(x34))
=> '0x7fdb5d318aa0'
hex(id(x34))
=> '0x7fdb5d318aa0'
x34
=> 30
hex(id(x34))
=> '0x7fdb5d318aa0'
x34=20
hex(id(x34))
=> '0x7fdb5d318960'
why does the address of the variable x34
change when I reassign it value 30
?
The fundamental misunderstanding you have is that id's belong to Python objects, not the variables. So, any reassignment to a new object, would cause the id's to change:
>>> x = (1,2)
>>> hex(id(x))
'0x107526e48'
>>> x = (2, 4)
>>> hex(id(x))
'0x107526e88'
Note, every time you create a new object, this happens:
>>> x = (1, 2)
>>> hex(id(x))
'0x107526e48'
>>> x = (1, 2)
>>> hex(id(x))
'0x107526d48'
>>> x = (1, 2)
>>> hex(id(x))
'0x107526dc8'
Immutability or lack thereof has nothing to do with it. Note, tuple
objects are immutable. However, there is a CPython implementation detail that small int
s are cached. This is why you'll see the following behavior:
>>> x = 10
>>> hex(id(x))
'0x10714d920'
>>> x = 10
>>> hex(id(x))
'0x10714d920'
>>> x = 10
>>> hex(id(x))
'0x10714d920'
Essentially, in CPython, int
objects between -5 and 256 are singletons. Just like None
:
>>> x = None
>>> id(x)
4413491112
>>> x = None
>>> id(x)
4413491112
However, this wont work the same way with large int
s, and works just like it does with tuple
s:
>>> x = 888
>>> hex(id(x))
'0x107550070'
>>> x = 888
>>> hex(id(x))
'0x10736aef0'
>>> x = 888
>>> hex(id(x))
'0x107550030'
Be careful, though, since id
is only guaranteed unique for the lifetime of the object. So, sometimes, you'll see the same memory being returned from the heap, since the Python interpreter tries to be efficient with memory:
>>> x = 888
>>> hex(id(x))
'0x107550050'
>>> x = 888
>>> hex(id(x))
'0x10736aef0'
>>> x = 888
>>> hex(id(x))
'0x107550090'
>>> x = 888
>>> hex(id(x))
'0x10736aef0'
>>> x = 888
>>> hex(id(x))
'0x107550070'
Again, this might happen with any object:
>>> x = object()
>>> hex(id(x))
'0x1072db120'
>>> x = object()
>>> hex(id(x))
'0x1072db110'
>>> x = object()
>>> hex(id(x))
'0x1072db120'
And the value of the object doesn't matter,
>>> x = 888
>>> hex(id(x))
'0x107549fd0'
>>> x = 999
>>> hex(id(x))
'0x107550090'
>>> x = 777
>>> hex(id(x))
'0x107549fd0'
Indeed, neither does the type necessarily matter either:
>>> class A:
... pass
...
>>> class B:
... pass
...
>>> class C:
... pass
...
>>> for i in range(12):
... if i%3 == 1:
... print(A())
... elif i%3 == 2:
... print(B())
... else:
... print(C())
...
<__main__.C object at 0x107535a58>
<__main__.A object at 0x107535a58>
<__main__.B object at 0x107535a58>
<__main__.C object at 0x107535a58>
<__main__.A object at 0x107535a58>
<__main__.B object at 0x107535a58>
<__main__.C object at 0x107535a58>
<__main__.A object at 0x107535a58>
<__main__.B object at 0x107535a58>
<__main__.C object at 0x107535a58>
<__main__.A object at 0x107535a58>
<__main__.B object at 0x107535a58>
This is all at the discretion of the interpreter implementation.
However, if you keep another reference to an object, the original will not die during reassignment, and that is guaranteed:
>>> hex(id(x))
'0x1072db140'
>>> y = x
>>> hex(id(y)) # guaranteed to be the same as x
'0x1072db140'
>>> x = object()
>>> hex(id(x)) # guaranteed to be new
'0x1072db130'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With