概要
- 題意の疑問は、pythonインタプリタの挙動を知ることで理解できます
結論
- それぞれ別の空間(
クラスオブジェクトとインスタンスオブジェクト)に定義、保持される- クラス定義内で記述したメソッドは
クラスオブジェクト内のクラス変数として定義される - イニシャライザで定義したメソッドは
インスタンスオブジェクト内のオブジェクト変数として定義される
- クラス定義内で記述したメソッドは
- 呼び出し時は、
インスタンスオブジェクトに定義されたメソッドが優先的に呼ばれ、インスタンスにて定義されていない場合にクラスオブジェクト側のメソッドが呼び出される
説明
- pythonでは、
クラスオブジェクトとインスタンスオブジェクトは別個のメモリ空間で定義されます - メソッド定義とイニシャライザは、それぞれ独立したタイミングで処理されます
- 具体的には、pythonインタプリタは以下のように処理します
-
クラスオブジェクトについて- クラス定義から
クラスオブジェクトを生成 - メソッド定義から
関数オブジェクトを生成
3. メソッド定義から関数オブジェクトをクラスオブジェクトの変数に代入
- クラス定義から
-
インスタンスオブジェクトについて-
インスタンスオブジェクト生成
2. インタプリタが__init__メソッドを実行
3.(__init__関数内でメソッドの代入が記述されていれば)インスタンスオブジェクトの変数に引数で渡された関数オブジェクトを代入
-
- メソッド呼び出し時
- インスタンス変数からメソッドを探索、実行
- 1で見つからなかった場合、クラス変数から探索、実行
-
テスト環境
- Python 3.10.12
- Ubuntu 22.04.4 LTS (WSL2)
テストコード
- クラス定義
class TestClass():
def __init__(self, arg_func=None):
if arg_func is not None:
self.method = arg_func
def __call__(self):
self.method()
def method(self):
print("original method called")
def arg_func():
print("arg func called")
def new_method(self):
print("new method called")
- 素のインスタンスと、イニシャライザに関数を渡したインスタンスのテスト
instance = TestClass(); instance()
instance = TestClass(arg_func); instance()
実行結果
original method called
arg func called
- クラスオブジェクト側のメソッドを上書きした場合
TestClass.method = new_method
instance = TestClass(); instance()
instance = TestClass(arg_func); instance()
実行結果
new method called
arg func called
謝辞
- コメントの @shiracamus 様、ありがとうございました