Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between a function, an unbound method and a bound method?

I'm asking this question because of a discussion on the comment thread of this answer. I'm 90% of the way to getting my head round it.

In [1]: class A(object):  # class named 'A'    ...:     def f1(self): pass    ...: In [2]: a = A()  # an instance 

f1 exists in three different forms:

In [3]: a.f1  # a bound method Out[3]: <bound method a.f1 of <__main__.A object at 0x039BE870>> In [4]: A.f1  # an unbound method Out[4]: <unbound method A.f1> In [5]: a.__dict__['f1']  # doesn't exist KeyError: 'f1' In [6]: A.__dict__['f1']  # a function Out[6]: <function __main__.f1> 

What is the difference between the bound method, unbound method and function objects, all of which are described by f1? How does one call these three objects? How can they be transformed into each other? The documentation on this stuff is quite hard to understand.

like image 801
Benjamin Hodgson Avatar asked Aug 14 '12 09:08

Benjamin Hodgson


People also ask

What is a bound method?

A bound method is the one which is dependent on the instance of the class as the first argument. It passes the instance as the first argument which is used to access the variables and functions. In Python 3 and newer versions of python, all functions in the class are by default bound methods.

What is unbound function?

Now, a function which is not bounded from above or below by a finite limit is called an unbounded function. For example: - x is an unbounded function as it extends from −∞ to ∞. Similarly, tanx defined for all real x except for x∈(2n+1)π2 is an unbounded function.

What is unbounded method?

Methods that do not have an instance of the class as the first argument are known as unbound methods. As of Python 3.0, the unbound methods have been removed from the language. They are not bounded with any specific object of the class.

What is Bound Unbound?

Form controls belong to one of three groups, depending on their data source as follows: Bound control – associated with a field in an underlying table. Use bound controls to display, enter, and update values from fields in the database. Unbound control – does not have a data source.


1 Answers

A function is created by the def statement, or by lambda. Under Python 2, when a function appears within the body of a class statement (or is passed to a type class construction call), it is transformed into an unbound method. (Python 3 doesn't have unbound methods; see below.) When a function is accessed on a class instance, it is transformed into a bound method, that automatically supplies the instance to the method as the first self parameter.

def f1(self):     pass 

Here f1 is a function.

class C(object):     f1 = f1 

Now C.f1 is an unbound method.

>>> C.f1 <unbound method C.f1> >>> C.f1.im_func is f1 True 

We can also use the type class constructor:

>>> 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> 

Unbound methods are bound by access on a class instance:

>>> C().f1 <bound method C.f1 of <__main__.C object at 0x2abeecf87250>> 

Access is translated into calling through the descriptor protocol:

>>> C.f1.__get__(C(), C) <bound method C.f1 of <__main__.C object at 0x2abeecf871d0>> 

Combining these:

>>> 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 unbound method is that the latter knows which class it is bound 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> 

Since the difference between a function and an unbound method is pretty minimal, Python 3 gets rid of the distinction; under Python 3 accessing a function on a class instance just gives you the function itself:

>>> C.f1 <function f1 at 0x7fdd06c4cd40> >>> C.f1 is f1 True 

In both Python 2 and Python 3, then, 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 (conventionally called self) to the instance. Thus the bound method C().f1 is equivalent to either of:

(lamdba *args, **kwargs: f1(C(), *args, **kwargs)) functools.partial(f1, C()) 
like image 133
ecatmur Avatar answered Oct 17 '22 08:10

ecatmur