0

I created a dummy class with two empty methods:

class Foo:
    def bar(self):
        pass
    def baz(self):
        pass

When I create an instance foo of my Foo class, why is id(foo.bar) == id(foo.baz) True even though the ids are obviously different?

>>> foo = Foo()
>>> id(foo.bar)
31344648
>>> id(foo.baz)
35951432
>>> id(foo.bar) == id(foo.baz)
True

However, using a function like this:

def is2(obj1, obj2):
    return id(obj1) == id(obj2)

The two methods' ids are no longer equal:

>>> foo = Foo()
>>> is2(foo.bar, foo.baz)
False
Markus Meskanen
  • 19,939
  • 18
  • 80
  • 119
  • Methods are created on demand and ids can be reused. – Martijn Pieters Jul 30 '15 at 16:32
  • @MartijnPieters But as you can see from the second piece of code, `id(foo.bar) == 31344648` and `id(foo.baz) == 35951432`, which are obviously not equal? Does the id suddenly change when I access two methods at once? – Markus Meskanen Jul 30 '15 at 16:33
  • The `id()` changes **all the time**. Run `id(foo.bar)` a few times in succession. Create a few other objects. Test again. Use `foo.bar is foo.baz` and see they are not the same object. – Martijn Pieters Jul 30 '15 at 16:35

1 Answers1

2

Methods are wrappers that are re-created on demand. Each time you refer to foo.baz a new method object is created.

Next, memory locations can be reused; id() values are only unique for the lifetime of an object. When the object no longer is needed (the reference count drops to 0) Python removes that object and is free to re-use the same memory space.

By doing id(foo.bar) the new method object only lives for the duration of the id() call. The next id(foo.baz) call is then free to reuse that memory location, and your == equality test returns true, purely because Python is being economic with memory allocation.

That the memory locations were not equal when you were testing the methods on separate lines is as much a coincidence that they were equal in the equality test. Neither is a given. Other objects are created in the interpreter at different stages and can end up reusing a memory location before the next method object is created, for example

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Alright thanks! Mind explaining the last part, my `is2()` function? `id(foo.bar) == id(foo.baz), is2(foo.bar, foo.baz)` returns `(True, False)` **Edit:** Nvm, I got it! They're function arguments and thus kept after the `id()` function's call. – Markus Meskanen Jul 30 '15 at 17:16