I modified your example a bit to better illustrate the options that I will use to explain the behavior
import inspect def print_id(obj): print "{} => {}".format(id(obj), obj) def getmember(obj, name):
However, if you are checking objects in REPL, the basic structure of your code will probably look like this:
#... foo = Foo() print_id(foo.bar) print_id(getattr(foo, 'bar')) print_id(getmember(foo, 'bar'))
The id() function basically returns the memory address of the object. That is, it is not an identity that is unique to all objects created during the entire program execution time. It is unique only to all objects that exist in the process at any given time.
The explanation, which corresponds to the difference between the two examples, is that resolving foo.bar any of the three ways gives you a new object each time . In the first example, these objects are stored in temporary variables, so all three must be located at different memory addresses.
In the second example, the associated method object is no longer needed after it is printed; Python reference count will free up its memory. This means that the next time the object of the associated method is created, it creates a new object created at the same memory address as the previous one. This is why it might seem that you are getting the same object multiple times.
The fact that you always get a new object of the associated method can be shown trivially:
>>> foo.bar == foo.bar True >>> foo.bar is foo.bar False
source share