Python id of function of instance is inconsistent

Question:

Please consider the following

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


a = A()
# accessing a's foo seems consistent
init1 = a.foo
init2 = a.foo
assert init1 == init2
assert id(a.foo) == id(a.foo)

# Or is it?
foos= [a.foo for i in range(10)]
ids = [id(foo) for foo in foos]
for i, id_ in enumerate(ids):
    for j, id__ in enumerate(ids):
        if i != j:
            assert id_ != id__

It appears id(a.foo) can equal to id(a.foo) and can not equal to id(a.foo), but I can’t understand when it is the same and when it isn’t.

Please explain what’s going on here.

Asked By: Gulzar

||

Answers:

The transformation of a function to an instance method happens every time the instance method attribute is accessed, so the id should be different every time, at least in the sense that a new object has been created. (see Python Data Model for details about method transformation and descriptors)

The problem is doing this:

assert id(a.foo) == id(a.foo)

There are times the Python garbage collector can work so fast that even within a single expression, two different objects can have the same id, because the object has already been reclaimed once id() is done with it.

If you do this:

assert id(init1) == id(init2)

you’ll see that they in fact have different ids.


Update: to address the question about why init1 == init2 is True: init1 and init2 are method wrapper objects that refer to the same function in the same class, so the method wrapper’s __eq__() considers them equal.

Answered By: sj95126

Note that the 2 id of the same id is not the same value:

for example:

a = 1 
b =1

print(id(a))
print(id(b))
print(id(a))

will give me this result:

9788992
9788992
9788992

but

print(id(id(a)))
print(id(id(a)))

will give this:

140331099421680
140331099421648

foos= [a.foo for i in range(10)] gives the same id valou to each one.

But the id of the id’s in foos is not the same value.

Therefore:

ids = [id(foo) for foo in foos]

Gives different values to each one.

Answered By: Aric a.

assert id(a.foo) is a type, not a number or variable.

each instance has a unique ID so ID of a.foo does not equal ID of a.foo’s second instance. You are looking for a boolean variable.(True/False)

So basically you are comparing something like the following:

# First instance (object in memory)
a.foo == building 1 apt 1
#second instance (object in memory)
a.foo ==building 1 apt 1

a.foo == a.foo  # boolean value "True"

# First instance of ID a.foo 
id(a.foo) == building 1 apt 1
# Second instance of ID a.foo
id(a.foo) == building 2 apt 1

id(a.foo) == id(a.foo) Boolean value "False".

While the above example is not technically correct. It gives you a better understanding of what is going on. What actually is happening is instance a.foo #1 gives a memory location and a.foo # 2 gives another memory location and even though the two values are the same the location in memory is not.

I hope this helps clarify things a bit for you.

Try this. add the following code to the end of your script:

 print(a)

 print(id(a))

Now run it 2 times. The ID’s change. and the memory location does too.

Answered By: Michael Mulvey
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.