A code snippet in Python 3 below has been discussed recently on the internet:
In : class A: ...: def method(self): ...: pass ...: ...: class B: ...: @classmethod ...: def method(cls): ...: pass In : A.method is A.method Out: True In : B.method is B.method Out: False
The question is why A.method returns the same object on each call while B.method returns the new one?
Let’s explore first what A.method really is:
In : A.method Out: <function __main__.A.method(self)> In : type(A.method) Out: function In : import inspect In : inspect.ismethod(A.method) Out: False
Essentially, what that means is that A.method is a function, i.e. unbound method of the class A. A great way to check if a method is indeed unbound is to check if its function object and a class instance exist:
In : hasattr(A.method, '__func__') Out: False In : hasattr(A.method, '__self__') Out: False
See Python documentation for more details, specifically an instance method subsection of the Data model section.
On the other hand, B.method is a class method. It returns an instance of the bound method object. Let’s check it:
In : B.method Out: <bound method B.method of <class '__main__.B'>> In : type(B.method) Out: method In : inspect.ismethod(B.method) Out: True In : hasattr(B.method, '__func__') Out: True In : hasattr(B.method, '__self__') Out: True In : B.method.__self__ is B Out: True In : B.method.__func__ Out: <function __main__.B.method(cls)>
That means on each B.method invocation a new object is created. You can achieve the same behaviour with A.method once the method gets bound:
In : a = A() In : id(a.method) Out: 140613204502216 In : id(a.method) Out: 140613210350280 In : id(a.method) Out: 140613209057096 In : a.method is a.method Out: False
Again, every time you call a.method a new bound method object is created.
The example above doesn’t apply to Python 2.7 though. It seems that Python 2.7 had different implementation, so that A.method would return different objects every time it’s called.