Bound vs Unbound Functions In Python

Let's start with a simple Python class Calculator with add method
class Calculator:
def add(self, numbers):
Now if you do the following, you will see func1 is an Unbound method whereas func2 is an bound method
func1 = Calculator.add
print (func1)
calc = Calculator()
func2 = calc.add
print (func2)
You will see the output as following
<function Calculator.add at 0x1028e88b0>
<bound method Calculator.add of <__main__.Calculator object at 0x1029fa7c0>>
Doesn't say much right? where as if you do the same in Python2
<unbound method Calculator.add>
<bound method Calculator.add of <__main__.Calculator instance at 0x10470db88>>


A bound method in Python is the method that has an object associated with it. Unbound method doesn't have an object associated with it.
The concept of “unbound methods” has been removed from the language as of 3.0. When referencing a method as a class attribute, you now get a plain function object.
If it's removed in 3.0 why should we care?
  1. 1.
    It's interesting to see how language features evolve
  2. 2.
    To compare and contrast these behaviors
Let me explain with an example. Try the following code both in Python2 and Python3
Python3 Output
add() missing 2 required positional arguments: 'self' and 'numbers'
Python2 Output
unbound method add() must be called with Calculator instance as the first argument (got nothing instead)
What does this tell us?
In Python3 unbound methods behave just like mere functions. Does that mean you can pass any random argument to it? Let's try
Calculator.add(1, 2)
The above snippet doesn't throw any error in Python3 whereas in Python2
TypeError: unbound method add() must be called with Calculator instance as first argument (got int instance instead)
If it is this helpful, ensures that you aren't playing around passing random arguments why did they remove it?

Why did Python3 Remove Unbound Methods?

Internet talks very little about why the unbound method was removed. Gudio himself gives us an idea in his blog
If you run the following snippet in Python2 it will throw an error exactly as above. Whereas Python3 doesn't
class Foo(object):
def bar(self):
self.val = 2
return self
class O(object):
pass # returns 2
This is called "Duck typing self"

Duck Typing Self

Duck-typing-self is the concept of defining the type of self dynamically at run time rather than restricting that it should be bound to the particular class type. In the above snippet, there is no Foo's bar function is called with a random object O
It is important to note that the "Duck typing self" is a side effect of removing unbound method and not the core reason
I asked the same on reddit, let's hope to find some answers