Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python reference to an new instance alternating

I have been playing with Python these days, and I realize some interesting way how Python assign id(address) to new instance (int and list).

For example, if I keep call id function with a number (or two different number), it return the same result. e.g.

>>> id(12345)
4298287048
>>> id(12345)
4298287048
>>> id(12345)
4298287048
>>> id(12342) #different number here, yet still same id
4298287048

Also when I declare the variable first and then call id() with it, the results are alternating like this.

>>> x = []; id(x)
4301901696
>>> x = []; id(x)
4301729448
>>> x = []; id(x)
4301901696
>>> x = []; id(x)
4301729448

Can someone please explain the Python work behind this? Also, is there a book or a site where I can read about this part of Python (assigning memory address, behind scene work, etc) since there is little I can find from python documentation

like image 516
Mike Lee Avatar asked Jun 06 '14 16:06

Mike Lee


1 Answers

You are creating a new object without any other references and Python re-uses the memory location when the object is destroyed again after id() is done with it. In CPython, the result of id() happens to be the memory location of the object. From the id() function documentation:

CPython implementation detail: This is the address of the object in memory.

The line id(12345) creates a new int() instance; because it is bound as an argument to id() it has 1 reference to it. id() determines the memory location, and returns that result. In returning, the arguments are cleaned up and the reference count to the int() instance drops to 0, and Python cleans it up. The memory is freed.

The next line creates a new int() instance. There is memory available at the same location, so it is reused.

When, instead, you first bind the new object no a name, you created an extra reference to the object and it is not cleared up. The memory is not freed, and a new object will have to use a new memory address.

This part too is documented, again from the id() documentation:

This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

Emphasis mine.

When rebinding (x = [] when x is already set) Python first creates a new object, then rebinds x to point to that new object. This unbinds the old list after the new list is created. This means the old memory location is still occupied when the new list object is created.

To map that out to specific steps:

  1. You create an object with id() == 4301901696.
  2. 4301901696 is bound to x -> Reference count for 4301901696 is 1.
  3. You create an object with id() == 4301729448.
  4. 4301901696 is unbound from x. Reference count for 4301901696 drops to 0 and is cleared from memory.
  5. 4301729448 is bound to x. Reference count for 4301729448 is 1.
  6. You create a new object, 4301901696 is empty so the new object gets id() == 4301901696.
  7. 4301729448 is unbound from x. Reference count for 4301729448 drops to 0 and is cleared from memory.
  8. 4301901696 is bound to x. Reference count for 4301901696 is 1.
  9. etc.

This too is part of the documentation, the assignment statement documenation tells you what order assignment takes place in:

An assignment statement evaluates the expression list [...] and assigns the single resulting object to each of the target lists, from left to right.

where expression list is everything on the right-hand-side of the = symbol.

like image 177
Martijn Pieters Avatar answered Sep 20 '22 21:09

Martijn Pieters