メインコンテンツへスキップ

Pythonのclassmethodとstaticmethodの使い分け

·1611 文字·4 分
目次

はじめに
#

Pythonのクラスにおいて、インスタンスメソッドとクラスメソッド (classmethod), スタティックメソッド (staticmethod) を使い分ける方法をまとめました。以下のように使い分けます。

  • インスタンスメソッド:インスタンス変数にアクセスする
  • クラスメソッド:インスタンス変数にアクセスせず、クラス変数にアクセスする
  • スタティックメソッド:インスタンス変数とクラス変数のどちらもアクセスしない

詳細は以下で述べます。

検証環境:Python 3.9.7

メソッドの使い分け
#

まず各メソッドの使い分けについて、以下のMyClassクラスを例に示します。

class MyClass:
    CONST = 10 # クラス変数

    def __init__(self, x):
        self.x = x # インスタンス変数

    def add0(self, y, z):
        # インスタンスメソッド
        return self.x + y + z

    @classmethod
    def add1(cls, y, z):
        # クラスメソッド
        return cls.CONST + y + z

    @staticmethod
    def add2(y, z):
        # スタティックメソッド
        return y + z

xはインスタンスごとに設定される変数で、インスタンス変数と呼びます。また、CONSTMyClass自体に設定されるので、クラス変数と呼びます。

add0メソッドのようにインスタンス変数にアクセスするメソッドは、インスタンスメソッドとして定義します。インスタンスメソッドの第1引数には、selfを取ります。selfはインスタンス自身を指す変数です(慣習的にselfを使っているだけで、Pythonの予約語ではありません)。 一方、add1メソッドのようにインスタンス変数は使用せず、クラス変数にのみアクセスするものは、@classmethodを付けて、クラスメソッドとして定義します。クラスメソッドの第1引数には、clsを取ります。clsはクラス自身を指す変数です(こちらも慣習的にclsを使っているだけで、Pythonの予約語ではありません)。 最後に、add2メソッドのように、インスタンス変数もクラス変数も使用しないものは、@staticmethodを付けて、スタティックメソッドとして定義します。スタティックメソッドの引数には、必要な変数のみ定義します。

なお、__init__はインスタンスの生成時に実行されるメソッドで、コンストラクタと呼びます。また、@classmethod@staticmethodは関数を装飾する仕組みであり、デコレータと呼びます。

クラスメソッド
#

各インスタンスはクラス変数にアクセスできるため、クラスメソッドは以下のようにインスタンスメソッドとして記述することも出来ます。

    def add1(self, y, z):
        return self.CONST + y + z

ただし、インスタンス変数にアクセスしない(インスタンス変数を変更しない)ことを明示するには、最初の例のように@classmethodを付けた方が良いでしょう。

スタティックメソッド
#

一方、スタティックメソッドとして定義可能なメソッドは、以下のようなインスタンスメソッドとして書くことも可能です。

    def add2(self, y, z):
        return y + z

しかし、PyLintで構文チェックを掛けると、以下のリファクタリングのメッセージが出力されます。

R0201 (no-self-use) Method could be a function

すなわち、「メソッドは関数として定義できる」という意味です。クラスの外にadd2メソッドを出してもロジック上は問題ないのですが、MyClassクラスの他のメソッドからadd2を呼び出している場合などは、クラスから出したくないこともあります。 そこで@staticmethodを付け、スタティックメソッドとして定義することで、PyLintのメッセージを出力しないようにできます。

また、@staticmethodを付けたご利益として、以下のようにインスタンスを定義せずにメソッドを使用できます。

>>> MyClass.add2(1, 2)
3

もしadd2をインスタンスメソッドとして定義すると、以下のように一度インスタンスを作った上でメソッドを実行する必要があります。

>>> my_class = MyClass(3)
>>> my_class.add2(1, 2)
3

参考
#

Helve
著者
Helve
関西在住、電機メーカ勤務のエンジニア。X(旧Twitter)で新着記事を配信中です

関連記事

Sphinxで生成するHTMLにSNSシェア用のOGPタグを設定する
·1359 文字·3 分
Sphinxで生成する記事のHTMLに、SNSで詳細情報を伝えるためのOGP (Open Graph Protocol) を導入する方法をまとめました。
Pythonパッケージのディレクトリ構成
·1651 文字·4 分
Pythonでパッケージを構築するときのディレクトリ構成(フォルダ構成)をまとめました。
Pythonで例外(エラー)クラスを自作する
·1670 文字·4 分
Pythonで自作の例外(いわゆるエラー)を実装する場合、新たなクラスとして定義します。
PEP 8によるPythonの命名規則
·773 文字·2 分
PythonのPEP 8に定められた、変数などの命名規則をまとめました。
PythonでSQLiteを扱う
Pythonのsqlite3ライブラリを使ってSQLiteを扱う方法をまとめました。
SphinxでMarkdown拡張言語のMySTを扱う
·1768 文字·4 分
SphinxでMarkdownの拡張言語であるMyST (Markedly Structured Text) を導入する方法をまとめました。