Pythonはクラス定義において三種類のメソッドをサポートしています:インスタンスメソッド、クラスメソッド、スタティックメソッド。それぞれは呼び出し方やクラスおよびインスタンスのデータへのアクセス方法によって異なります。
歴史的背景:
当初、インスタンスメソッド(「self」を持つもの)は唯一の動作タイプであり、メソッドは常に特定のオブジェクトの動作を呼び出す、またはデータを変更/読み取ることを意図していました。その後、Pythonにはクラス全体の動作を提供するクラスメソッド(「cls」を持つもの)や、通常の関数に似ているがクラスに関連付けられたスタティックメソッドが登場しました。
問題点:
時にはすべてのインスタンスのための共通機能(スタティックメソッド)が必要になります。また、時には「クラス全体に対して」利用可能な操作が必要になります(例えば、インスタンスの作成)。このとき、メソッドタイプを間違えて特定できないと、バグが発生することがあります(例えば、インスタンスメソッドを通じてクラスを変更しようとしたり、その逆)。
解決策:
コードの例:
class MyClass: def instance_method(self): return f"インスタンス: {self}" @classmethod def class_method(cls): return f"クラス: {cls}" @staticmethod def static_method(): return "これはスタティックメソッドです" obj = MyClass() print(obj.instance_method()) # インスタンス: <MyClass object...> print(MyClass.class_method()) # クラス: <class 'MyClass'> print(MyClass.static_method())# これはスタティックメソッドです
主な特徴:
クラスを介してインスタンスメソッドを直接呼び出すことはできますか?
できますが、オブジェクトを明示的に渡す必要があります:
MyClass.instance_method(obj)
これはあまり適切ではありません。
継承におけるスタティックメソッドの振る舞い:オーバーライド可能ですか?
はい、同じ名前で子クラスにstaticmethodを宣言することができ、呼び出し元が継承クラスからの場合、そのメソッドが呼び出されます。
クラスメソッドは何のために使われるのですか?スタティックメソッドとclsを引数にすれば常に使えますか?
clsは単なる最初の引数ではありません:classmethodでは、Pythonが自動的に呼び出し元のクラスをclsとして挿入します。これにより、親に厳密に結びつかない代替コンストラクタの階層を作成できるようになります。
例:
class Base: @classmethod def make(cls): return cls() class Child(Base): pass Child.make() # Childを返す、Baseではない
プロジェクトでは、代替インスタンスを作成するために通常のメソッドが使用されていました(例えば、create_from_json)。これにより、継承時にメソッドが常に基底クラスのオブジェクトを返し、子クラスではなくなりました。
利点:
欠点:
現在のクラスのインスタンスを返すclassmethodファクトリが実装され、継承クラスから呼び出されても(cls())機能します。
利点:
欠点: