Search code examples
pythonpython-2.7

About the behaviour of id on an instance method


I have the following script:

class A(object):
    def f(self):
        pass

a = A()
b = A()
print map(id, [A.f, a.f, b.f])
print map(id, [a.f, b.f]) 

Out:

[4299312976, 4298026672, 4299370816]
[4299312976, 4298026672]
  • why does the id of A.f become the id of a.f?
  • why does the id of a.f become the id of b.f?

Now I do this:

print "{0} {1} {2}".format(id(A.f), id(a.f), id(b.f))

Out:

4299312976 4299312976 4299312976

Why do they have the same id now?


Solution

  • When you access A.f an object is created, of type <unbound method>. You can see this is the case with:

    print map(id, [A.f, A.f, A.f])
    

    where the id value won't be the same. The same happens for a.f and b.f but in this case the type is <bound method> because the object remembers which instance the code needs to act on.

    These objects are garbage collected once you don't reference them any more. So:

    map(id, [A.f, a.f, b.f])
    

    creates 3 objects (4 including the list containing them) and passes them to the function id. Once the map call is terminated list and the objects are collected and memory is freed.

    In the second call new objects are created and the memory for the object created for A.f has been reused (thus you get he same id).

    In the last example you're calling id each time explicitly on an object that is immediately discarded, and the memory happens to be reused immediately.

    This apparently "magical" object creation when accessing a method happens because of descriptors.