Data Model

Bound and Unbound Methods

instance.method binds self automatically; Class.method is a plain function.

instance.method returns a bound method. The method already remembers the instance through __self__, so calling it does not require passing self again.

Source

class Counter:
    def __init__(self, start=0):
        self.value = start

    def increment(self):
        self.value += 1
        return self.value

bound_counter = Counter(10)
m = bound_counter.increment
print(m.__self__ is bound_counter)
print(m())
print(m())

Output

True
11
12
obj.methodbound · self filledClass.methodfunction · self required
Accessing a method via an instance binds self; accessing it via the class returns the underlying function.

Class.method returns the underlying function — there is no self attached. Calling it requires passing the instance as the first argument explicitly. Using a fresh counter here makes the output independent of the previous cell.

Source

unbound_counter = Counter(0)
unbound = Counter.increment
print(type(unbound).__name__)
print(unbound(unbound_counter))
print(unbound(unbound_counter))

Output

function
1
2

Bound methods are first-class values. They can be stored in lists, passed to other functions, and called later. Each bound method carries its own __self__, so two methods produced from two different instances stay independent.

Source

handlers = []
for _ in range(2):
    handlers.append(Counter().increment)

print(handlers[0]())
print(handlers[0]())
print(handlers[1]())

Output

1
2
1

The binding is the descriptor protocol at work. The function lives on the class as a plain function; instance attribute access invokes __get__, which returns a bound method that knows the instance.

Source

descriptor_counter = Counter(0)
func = Counter.__dict__["increment"]
print(type(func).__name__)
rebound = func.__get__(descriptor_counter, Counter)
print(type(rebound).__name__)
print(rebound.__self__ is descriptor_counter)

Output

function
method
True

Notes

See also

Run the complete example

Example code

Expected output

True
11
12
function
1
2
1
2
1
function
method
True

Execution time appears here after you run the example.