Differencebetween a Function, an Unbound Method and a Bound Method

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

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

Class method differences in Python: bound, unbound and static

In Python, there is a distinction between bound and unbound methods.

Basically, a call to a member function (like method_one), a bound function

a_test.method_one()

is translated to

Test.method_one(a_test)

i.e. a call to an unbound method. Because of that, a call to your version of method_two will fail with a TypeError

>>> a_test = Test() 
>>> a_test.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)

You can change the behavior of a method using a decorator

class Test(object):
def method_one(self):
print "Called method_one"

@staticmethod
def method_two():
print "Called method two"

The decorator tells the built-in default metaclass type (the class of a class, cf. this question) to not create bound methods for method_two.

Now, you can invoke static method both on an instance or on the class directly:

>>> a_test = Test()
>>> a_test.method_one()
Called method_one
>>> a_test.method_two()
Called method_two
>>> Test.method_two()
Called method_two

What's the difference between a 'function', 'method' and 'bound method' in Python 3?

Is 'method' a type equivalent to 'unbound method' in Python 2?

Kind-a-sort-a. But not really. It is a method_descriptor object defined in C code. It is an unbound method, but not the kind you found in Python 2.

For Python types written C, all 'methods' are really C functions. The <method 'name' of 'type' objects> object you found is a special object you can use to call that function given an instance and further arguments, just like the function object does for custom Python classes. The object is defined in C in the PyMethodDescr_Type structure. It implements the descriptor protocol, just like functions do.

Python defines several other such descriptor types; if you use __slots__, each attribute is a dsescriptor of type member_descriptor (see the PyMemberDescr_Type structure), while classmethod, property and staticmethod are perhaps better known descriptor objects.

In Python 2, bound and unbound methods are really just one type, instancemethod (defined by the PyMethod_Type structure); it'll report as bound if the __self__ (im_self) attribute is set. In Python 3 using a function as a descriptor simply doesn't produce method objects without __self__ set; instead calling function.__get__() with no instance just returns the function again.

The only reason Python 2 returns unbound methods is to enforce a type check; the first argument must be an instance of the class (or a subclass thereof). This didn't make all that much sense for Python code that supports duck-typing, so in Python 3 the restriction was removed. However, with C code you can't use duck-typing, you still have to restrict the type, and that's why C-types still return a method_descriptor object that enforces this restriction.

Differences between methods of a class, which are function and which are bound method ?

This answer will be really technical, I hope it's still understandable though. The problem is that it requires knowledge of the descriptor protocol to understand how methods in Python work.

All functions in Python 3 are descriptors, to be precise they are non-data descriptors. That means they implements a __get__ method - but no __set__ method.

That's interesting because descriptors can do (almost) anything if they are looked up on a class or an instance.

By the definition of the __get__ method in Pythons data model:

object.__get__(self, instance, owner)

Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise an AttributeError exception.

So what does this have to do with the difference between function and bound_method?

It's easy, a function accessed through __get__ with an instance=None will return itself:

>>> def func(x): return x
>>> func.__get__(None, object)
<function __main__.func>
>>> func.__get__(None, object) is func
True

While it will be a bound_method if accessed with an not-None instance:

>>> func.__get__(object())
<bound method func of <object object at 0x00000155614A0610>>

It's basically just a wrapper around func with the instance stored:

>>> m = func.__get__(object())
>>> m.__self__ # stored instance
<object at 0x155614a0650>

>>> m.__func__ # stored function
<function __main__.func>

However, when called, it will pass the instance as first argument to the wrapped function:

>>> m()
<object at 0x155614a0650>

So, bound methods will pass the instance as first argument, while functions do not (they requires all attributes).


So when you look at a class all normal methods will display as functions while all normal methods on an instance will be bound methods.

Why did I mention normal methods? Because you can define arbitrary descriptors. For example the Python built-ins already contain several exceptions:

  • classmethod
  • staticmethod
  • property (this is in fact a data-descriptor so I'll neglect it in the following discussion)

classmethods will display as bound method even when looked up on the class. That's because they are meant to be callable on the class and pass the class to the function, no matter if they are called on the class or the instance:

class Test(object):
@classmethod
def func(x):
return x

>>> Test.func
<bound method Test.func of <class '__main__.Test'>>
>>> Test().func
<bound method Test.func of <class '__main__.Test'>>

And staticmethods always display as functions because they never pass anything additional to the function:

class Test(object):
@staticmethod
def func(x):
return x

>>> Test().func
<function __main__.Test.func>
>>> Test.func
<function __main__.Test.func>

So it's easily possible to see also bound methods on the class (e.g. classmethods) and likewise one could also find normal functions on instances (e.g. staticmethods).

is it necessary to distinguish method and function in python3?

As a matter of terminology, methods are attached to class instances (or classes themselves, for classmethods and staticmethods), functions aren't.

In practice, in Python 3, the distinction is much weaker than it used to be. Originally, in Python 2, "methodness" was more important; defining a function within a class made it an unbound method if referenced from the class, and a bound method if referenced on the instances.

In Python 3, the concept of unbound methods is gone; when referenced from the class itself, you get a plain function, not a method (bound or unbound); you only get a bound method when you reference the method from an instance of the class.

Essentially, there are really two categories of things now:

  1. Functions which can't be bound as methods (because they don't implement the descriptor protocol to produce bound methods; applies solely to built-in functions in CPython)
  2. Functions which can be bound as methods (includes all functions defined in Python itself)

Everything in category 2 is a function which can act as a method if attached to a class, then referenced from an instance of said class. The nomenclature describes the intent, but as a matter of implementation, there is very little difference left.

Note that even in Python 2, the two category approach was the same, it's just that the descriptor protocol for functions was invoked even when loaded from the class itself (to bypass it and get the raw function without creating an unbound method, you had to do ClassName.__dict__['methodname']). So it's always been the case that methods are just the result of binding functions as a matter of implementation.

id()s of bound and unbound method objects --- sometimes the same for different objects, sometimes different for the same object

Whenever you look up a method via instance.name (and in Python 2, class.name), the method object is created a-new. Python uses the descriptor protocol to wrap the function in a method object each time.

So, when you look up id(C.foo), a new method object is created, you retrieve its id (a memory address), then discard the method object again. Then you look up id(cobj.foo), a new method object created that re-uses the now freed memory address and you see the same value. The method is then, again, discarded (garbage collected as the reference count drops to 0).

Next, you stored a reference to the C.foo unbound method in a variable. Now the memory address is not freed (the reference count is 1, instead of 0), and you create a second method instance by looking up cobj.foo which has to use a new memory location. Thus you get two different values.

See the documentation for id():

Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

CPython implementation detail: This is the address of the object in memory.

Emphasis mine.

You can re-create a method using a direct reference to the function via the __dict__ attribute of the class, then calling the __get__ descriptor method:

>>> class C(object):
... def foo(self):
... pass
...
>>> C.foo
<unbound method C.foo>
>>> C.__dict__['foo']
<function foo at 0x1088cc488>
>>> C.__dict__['foo'].__get__(None, C)
<unbound method C.foo>
>>> C.__dict__['foo'].__get__(C(), C)
<bound method C.foo of <__main__.C object at 0x1088d6f90>>

Note that in Python 3, the whole unbound / bound method distinction has been dropped; you get a function where before you'd get an unbound method, and a method otherwise, where a method is always bound:

>>> C.foo
<function C.foo at 0x10bc48dd0>
>>> C.foo.__get__(None, C)
<function C.foo at 0x10bc48dd0>
>>> C.foo.__get__(C(), C)
<bound method C.foo of <__main__.C object at 0x10bc65150>>

Furthermore, Python 3.7 adds a new LOAD_METHOD - CALL_METHOD opcode pair that replaces the current LOAD_ATTRIBUTE - CALL_FUNCTION opcode pair precisely to avoid creating a new method object each time. This optimisation transforms the executon path for instance.foo() from type(instance).__dict__['foo'].__get__(instance, type(instance))() with type(instance).__dict__['foo'](instance), so 'manually' passing in the instance directly to the function object.

Python: Bind an Unbound Method?

All functions are also descriptors, so you can bind them by calling their __get__ method:

bound_handler = handler.__get__(self, MyWidget)

Here's R. Hettinger's excellent guide to descriptors.


As a self-contained example pulled from Keith's comment:

def bind(instance, func, as_name=None):
"""
Bind the function *func* to *instance*, with either provided name *as_name*
or the existing name of *func*. The provided *func* should accept the
instance as the first argument, i.e. "self".
"""
if as_name is None:
as_name = func.__name__
bound_method = func.__get__(instance, instance.__class__)
setattr(instance, as_name, bound_method)
return bound_method

class Thing:
def __init__(self, val):
self.val = val

something = Thing(21)

def double(self):
return 2 * self.val

bind(something, double)
something.double() # returns 42


Related Topics



Leave a reply



Submit