The function is created by the def or lambda operator. In Python 2, when a function appears in the body of a class statement (or is passed to a call to the construction of a type class), it is converted to an unbound method. (Python 3 has no unrelated methods, see below.) When a class instance is accessed by a function, it is converted to the bound method, which automatically passes the instance to the method as the first parameter of self .
def f1(self): pass
Here f1 is a function.
class C(object): f1 = f1
C.f1 is now an unrelated method.
>>> C.f1 <unbound method C.f1> >>> C.f1.im_func is f1 True
We can also use the constructor of the type class:
>>> C2 = type('C2', (object,), {'f1': f1}) >>> C2.f1 <unbound method C2.f1>
We can convert f1 to an unbound method manually:
>>> import types >>> types.MethodType(f1, None, C) <unbound method C.f1>
Unrelated methods are bound by access to the class instance:
>>> C().f1 <bound method C.f1 of <__main__.C object at 0x2abeecf87250>>
Access is converted to a call through the descriptor protocol:
>>> C.f1.__get__(C(), C) <bound method C.f1 of <__main__.C object at 0x2abeecf871d0>>
Combining them:
>>> types.MethodType(f1, None, C).__get__(C(), C) <bound method C.f1 of <__main__.C object at 0x2abeecf87310>>
Or directly:
>>> types.MethodType(f1, C(), C) <bound method C.f1 of <__main__.C object at 0x2abeecf871d0>>
The main difference between a function and an unrelated method is that the latter knows which class it is attached to; calling or binding an unbound method requires an instance of its class type:
>>> f1(None) >>> C.f1(None) TypeError: unbound method f1() must be called with C instance as first argument (got NoneType instance instead) >>> class D(object): pass >>> f1.__get__(D(), D) <bound method D.f1 of <__main__.D object at 0x7f6c98cfe290>> >>> C.f1.__get__(D(), D) <unbound method C.f1>
Because the difference between a function and an unbound method is pretty minimal, Python 3 gets rid of the difference; under Python 3, accessing a function in an instance of a class simply gives you the function itself:
>>> C.f1 <function f1 at 0x7fdd06c4cd40> >>> C.f1 is f1 True
In both Python 2 and Python 3, these three are equivalent:
f1(C()) C.f1(C()) C().f1()
Binding a function to an instance has the effect of fixing its first parameter (conditionally called self ) to the instance. Thus, the associated method C().f1 equivalent to any of:
(lamdba *args, **kwargs: f1(C(), *args, **kwargs)) functools.partial(f1, C())