概要
- 題意の疑問は、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 様、ありがとうございました