Python のメソッドとバウンドメソッドの仕組み

Python の「メソッド」は、関数がインスタンスに束縛されたものです。関数とバウンドメソッドの違いを理解すると、Python のオブジェクトモデルが明確になります。

関数とメソッドの違い

class Calculator:
    def add(self, a, b):
        return a + b

calc = Calculator()

# クラスから取得:関数
func = Calculator.add
print(type(func))  # <class 'function'>

# インスタンスから取得:バウンドメソッド
method = calc.add
print(type(method))  # <class 'method'>

バウンドメソッドの構造

バウンドメソッドは、関数と束縛されたインスタンスへの参照を保持しています。

print(method.__func__)  # <function Calculator.add>
print(method.__self__)  # <Calculator object>

バウンドメソッドを呼び出すと、__self__ が自動的に第一引数として渡されます。

# 以下は同じ結果
print(calc.add(1, 2))              # 3
print(Calculator.add(calc, 1, 2))  # 3
print(method(1, 2))                # 3

動的なメソッドバインディング

関数を後からインスタンスにバインドすることもできます。

import types

def greet(self):
    return f"Hello, {self.name}!"

class Person:
    def __init__(self, name):
        self.name = name

p = Person("Alice")
p.greet = types.MethodType(greet, p)
print(p.greet())  # Hello, Alice!

アンバウンドメソッド(Python 2 との違い)

Python 2 ではクラスから取得したメソッドは「アンバウンドメソッド」でしたが、Python 3 では単なる関数として扱われます。

Python 2

クラス.メソッド → アンバウンドメソッド(self の型チェックあり)

Python 3

クラス.メソッド → 単なる関数(型チェックなし)

この変更により、Python 3 ではダックタイピングがより柔軟になりました。