Python creates a new bound method object every time you access f
(see Does Python really create all bound method for every new instance?).
In the first loop:
- At the first iteration:
obj.f
creates the bound method object.
who
prints the id
- There are no more references to the bound method object, hence it is deallocated immediately by the interpreter
- At the following iteration:
obj.f
creates a new bound method object. The intrepreter reuses the memory freed at the iteration before.
who
prints the id which happen to match the previous id
- Again the object is deallocated
In the second loop:
- At the first iteration
obj.f
creates a new bound method object
- It is assigned to
tmp
(and thus it has a reference now)
who
prints the id
- No deallocation is performed. The
tmp
variable keeps the object alive
- At the following iteration
obj.f
creates a new bound method object. It cannot reuse the old address because that object is still alive.
- It is assigned to
tmp
. Now the old value of tmp
has no more references and thus is deallocated.
who
prints the id, which is a new one.
- Again no deallocation occurs
- At the following iteration
obj.f
creates a new bound method object. Now the old-old address is again available and the interpreter decides to reuse it.
- It is assigned to
tmp
. Now the old value of tmp
has no more references and thus is deallocated.
who
prints the id, which is a old-old one
- Again no deallocation occurs
and so a loop is created that alternates between the two addresses.
By using more variables you can create longer cycles:
>>> tmp1 = obj.f
>>> tmp2 = tmp3 = tmp4 = tmp5 = None
>>> for i in range(20):
... tmp5 = tmp4
... tmp4 = tmp3
... tmp3 = tmp2
... tmp2 = tmp1
... tmp1 = obj.f
... who(tmp1)
...
864 896 560 280 288 864 896 560 280 288 864 896 560 280 288 864 896 560 280 288
Or, as mentioned by Reblochon Masque in his answer, using del
you can avoid the behaviour:
>>> for i in range(20):
... tmp = obj.f
... who(tmp)
... del tmp # forget the name
...
688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688
Note that this is due to implementation details of CPython. In Jython or other python implementations without reference counting both loops will probably behave pretty much in the same way: showing ten different ids.