-2

Edit

I wouldn't have asked this question if I would have written an adapted code that would have impeded the quirk occuring in the use of the memory (see user2357112's answer)

With the following code, all is normal and understandable:

from copy import deepcopy

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

d = {}
def N(obj):
    i = id(obj)
    return '  %d  %s' % (i, d.setdefault(i,len(d)))

print 'A.f',N(A.f)

du1 = dict((j,str(j)) for j in xrange(50000))
w = A.f
print 'w  ',N(w)

print 'A.f',N(A.f)

du2 = deepcopy(du1)
x = A.f
print 'x  ',N(x)

print 'A.f',N(A.f)

du3 = deepcopy(du1)
y = A.f
print 'y  ',N(y)

print '------------------------------'
del y
du4 = deepcopy(du1)
print 'A.f',N(A.f)
print 'w  ',N(w)
print 'x  ',N(x)

print 
del x
du5 = deepcopy(du1)
print 'A.f',N(A.f)
du6 = deepcopy(du1)
print 'w  ',N(w)

del w
du7 = deepcopy(du1)
print 'A.f',N(A.f)

result

A.f   18668040  0
w     18669040  1
A.f   18668080  2
x     18668000  3
A.f   18668760  4
y     18731616  5
------------------------------
A.f   18669120  6
w     18669040  1
x     18668000  3

A.f   18669080  7
w     18669040  1
A.f   18781928  8

This result shows that each time an atribute reference is done to the method attribute, a method object is created, as it is explained by Martijn in the code referenced as the one to which my question is said duplicate.

original question

I can"t explain what happens during the following execution.

Don't pay too much attention to the function N(), I used it to make easier to dinstinguish the identities returned by id() because sometimes the identities of two objects, though different, are very similar, like 18717912 and 18717192 for example.

The point is that the identity of the method at one moment depends on the bindings it has formerly undergone, pushing to think that the method doesn't remain the same object !
And progressively deleting the identifiers appeared during the successive bindings makes the identity of the method to recover its past values !!!

What's this mess ?

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

d = {}
def N(obj):
    i = id(obj)
    return '  %d  %s' % (i, d.setdefault(i,len(d)))

print 'A.f',N(A.f)

w = A.f
print '----w = A.f------'
print 'A.f',N(A.f)
print 'w  ',N(w)

x = A.f
print '----x = A.f------'
print 'A.f',N(A.f)
print 'x  ',N(x)
print 'w  ',N(w)

y = A.f
print '----y = A.f------'
print 'A.f',N(A.f)
print 'y  ',N(y)
print 'x  ',N(x)
print 'w  ',N(w)
             
z = A.f
print '----z = A.f------'
print 'A.f',N(A.f)
print 'z  ',N(z)
print 'y  ',N(y)
print 'x  ',N(x)
print 'w  ',N(w)

del z
print '\n----del z--------'
print 'A.f',N(A.f)
print 'y  ',N(y)
print 'x  ',N(x)
print 'w  ',N(w)

del x
print '----del x--------'
print 'A.f',N(A.f)
print 'y  ',N(y)
print 'w  ',N(w)

del w
print '----del w---------'
print 'A.f',N(A.f)
print 'y  ',N(y)

del y
print '----del y---------'
print 'A.f',N(A.f)

result

A.f   18668040  0
----w = A.f------
A.f   18668760  1
w     18668040  0
----x = A.f------
A.f   18732336  2
x     18668760  1
w     18668040  0
----y = A.f------
A.f   18669120  3
y     18732336  2
x     18668760  1
w     18668040  0
----z = A.f------
A.f   18732496  4
z     18669120  3
y     18732336  2
x     18668760  1
w     18668040  0

.

----del z--------
A.f   18669120  3
y     18732336  2
x     18668760  1
w     18668040  0
----del x--------
A.f   18668760  1
y     18732336  2
w     18668040  0
----del w---------
A.f   18668040  0
y     18732336  2
----del y---------
A.f   18732336  2
Community
  • 1
  • 1
eyquem
  • 26,771
  • 7
  • 38
  • 46
  • @mattm I expected all the identities of ``A.f``, ``w``, ``x``, ``y``, ``z`` to be and remain the same during the whole execution because I thought the method object was ... an object, and _"Every object has an identity, a type and a value. An object’s identity never changes once it has been created"_ [in the doc](http://docs.python.org/2/reference/datamodel.html#objects-values-and-types) – eyquem Jan 20 '14 at 02:14

1 Answers1

4

Python doesn't keep canonical method objects. Every time you access a method, you get a newly created method object:

>>> OrderedDict.update is OrderedDict.update
False

Every time you printed the ID of A.f, that was a new A.f object. The fact that old ID values were reused when old objects were deleted is a quirk of the allocator and garbage detector; the storage of recently-released objects is frequently used to represent newly-created objects.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • _"Every time you access a method, you get a newly created method object"_ That was what I had understood for a long time in the following excerpt of [the doc](http://docs.python.org/2/tutorial/classes.html#method-objects) : _"When an instance attribute is referenced that isn’t a data attribute, its class is searched. If the name denotes a (...) function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object."_ But this excerpt isn't fully explicit and I had a doubt. – eyquem Jan 20 '14 at 04:10
  • Moreover, it had became more evident when I undesrtood that methods are implemented as descriptor function; and I even tested codes with creation of objects to occupy the memory because I had thought to the quirk you described. But the occupying objects I used weren't massive enogh, and they didn't empeded the described quirk concerning the memory to happen ! So I was leaded to a comp^lete misunderstanding. - I find that the doc doesn't explain enough clearly the stuff concerning the methods. - Thank you very much for your answer. – eyquem Jan 20 '14 at 04:17
  • Now with your answer and the Martijn's answer in the given link, I am quite sure that a method doesn't exist apart from the moment it is in action if a binding hasn't been done to it. I find this fact completely unevident. – eyquem Jan 20 '14 at 04:22
  • However, list.append is list.append; when does it change? For any non-builtin type only? – Bach Jan 20 '14 at 07:36
  • @HansZauber: Dunno. My guess is that unbound methods of built-in types are the only exception, but I have not performed thorough tests or deep examination of the source code. – user2357112 Jan 20 '14 at 09:05