0

As below, id(a.__getattribute__) return different value when __getattr__ method defined. How did this happened? (My Python is v3.7.0)

class A():

    def __getattribute__(self,key):
        print(key)
        return super().__getattribute__(key)
    def f():
        pass
    def __getattr__(self,key):
        print(key)
        return super().__getattr__(key)


a=A()
print('id(a.__getattribute__)')
print(id(a.__getattribute__))
print(id(a.__getattribute__))
print(id(a.__getattribute__))
print(id(a.__getattribute__))

Output results:

id(a.__getattribute__)
__getattribute__
44147656
__getattribute__
12643664
__getattribute__
44147656
__getattribute__
12643664

When comment __getattr__:

...
##        def __getattr__(self,key):
##            print(key)
##            return super().__getattr__(key)
...

Output results:

id(a.__getattribute__)
__getattribute__
11005264
__getattribute__
11005264
__getattribute__
11005264
__getattribute__
11005264
Cleptus
  • 3,446
  • 4
  • 28
  • 34
Jorden
  • 3
  • 1
  • 2
    The ids are different every time you run the program, with or without `__getattr__`... – Aran-Fey Oct 28 '18 at 17:10
  • 2
    @Aran-Fey what OP meant is that with `__getattr__` they are always different, whereas without `__getattr__` defined the value is the same for every call. – Alessandro Cosentino Oct 28 '18 at 17:13
  • Oh, I think I understand what you're asking about. Whenever `__getattr__` is commented out, the same id is printed 4 times. But when `__getattr__` exists, every 2nd id is different. Still, that doesn't *always* happen. It's basically just coincidence. – Aran-Fey Oct 28 '18 at 17:13
  • @Aran-Fey I have so far not been able to catch a case where this did not happen. Strangely enough, ``__getattr__`` itself is never called. – MisterMiyagi Oct 28 '18 at 17:19
  • Save `x = a.__getattribute__` to different variables then try, `id(x), id(y) ` etc – juanpa.arrivillaga Oct 28 '18 at 17:20
  • It's just in the SAME program got defferent values from four `print` statements) when __getattr__ defined but got same value if undefined. – Jorden Oct 28 '18 at 17:23
  • Related: [Why is this false? `SomeClass.method is SomeClass.method`](https://stackoverflow.com/q/49765019/674039) – wim Oct 28 '18 at 18:56

1 Answers1

1

Whenever you do an instance.method lookup, you'll always get a new bound method object. This binding is how the self argument gets passed to the function (the lookup of the method binds the instance to a function that was in the class dictionary).

Whether you get a method with the same id or not has to do with how Python computes those id values. The values you get from id are guaranteed to be unique, but only among objects that exist at the same time. After one object is garbage collected, another object with the same ID may be created.

CPython produces ids based on the memory address of the object. The same memory will be often reused for different bound method objects at different times, since caching memory is much faster than always using new memory. Exactly when this reuse happens is an implementation detail. Other Python interpreters (like PyPy or Jython) and even other versions of CPython may do it differently or not at all. You should never rely upon the specific details of this behavior (or any other details of the specific values you get from id). The only thing you should rely on id for is that it will always be different for objects that exist simultaneously.

I suspect it is coincidence that changing the number of methods in your class changes the behavior of id reuse. Perhaps there is a reason for it (e.g. something in the class machinery is creating one extra bound method object somewhere), but there is no possible benefit you can get from knowing the exact cause. The details are going to be very implementation specific, and so you should never rely upon them, as if you do, they may change and break your code without warning.

Blckknght
  • 100,903
  • 11
  • 120
  • 169