I have an idea why the python object returned by obj.method can be different each time you reference obj.method, and why objA.methodA and objectB.methodB can both return the same object: The object returned when you reference an instance method is a temporary object, the Python equivalent of a C stack pointer.
Python allows recursion. This means each time you execute a function (or method) python has to create an object to hold the program counter and all the local variables for the function call. I think that is what you are getting when you call a.__init__ or a.test in your example. Python is creating "function context" object that implements __call__(). This is why id(a.test) may print different values at different times. You are displaying the object ID of a temporary object.
To test my theory I called made this class:
class A():
def method():
pass
Then I made an instance of A and called id(a.method) multiple times:
Output:
>>> a = A()
>>> id(a.method)
2410911802112
>>> id(a.method)
2410910939520
>>> id(a.method)
2410911802624
>>> id(a.method)
2410911802112
>>> id(a.method)
2410911802624
Notice the id values are different, but repeat.
Next I started assigning variables to a.method.
Output:
>>> x = a.method
>>> y = a.method
>>> z = a.method
>>> id(x)
2410910955584
>>> id(y)
2410911802112
>>> id(z)
2410915105600
>>> id(a.method)
2410915105792
>>> id(a.method)
2410915105856
>>> id(a.method)
2410910939520
>>> id(a.method)
2410915105792
The objects referenced by variables x, y and z are all different. I tried several more variables, and these all get different objects. The objects referenced by these variables no longer appear when I call id(a.method) which still returns different but repeating values.
Assigning the result of a.method to a variable increments the object count, so it will not get garbage collected. I think that is why calling "x = a.method" removes the id(x) from the values that appear when I call id(a.method). This is a good indication that a.method is returning a generated object, not an attribute. If a.method was an attribute it's reference count would not go to zero and it would not be garbage collected. If a.method was an attribute it would also return the same object every time. Instead a.method works like a generator property. It creates a new object when referenced.
I wonder how far off this is from what is actually happening.