ソフトな忘却力(115) Pythonのデコレータ、クラスメソッド、インスタンスメソッド

Joseph Halfmoon

「サイエンティフィックPythonのための」IDE、Spyder上にてScientific Python Lecturesの実習中。デコレータの練習が続いてます。今回は処理系に備わっているデコレータ2つ、classmethod、staticmethodの復習です。Class定義するときになんとなく使っている奴ら。

※「 ソフトな忘却力」投稿順 Index はこちら

※Sypder IDEはWindows版 6.0.7使用です。Python処理系はPython 3.11.12です。

Scientific Python Lectures様のコースは例題だけでなく、エクササイズなども充実、それを全部順番に解いていったら必ずや立派な人になれるだろ~と思います。でも老い先短い年寄には量が多過ぎて多分死ぬまでに終わりません。適当な練習でお茶を濁してます。今回は「7.2 Decorators」の「7.2.4 Examples in the standard library」です。

classmethodとstaticmethod

このところ、デコレータを定義して使ってみるの回がつづきましたが、今回は、「何も書かずとも使える」デコレータ2つです。

    • classmethod
    • staticmethod

いずれもClassを定義するときに、メソッド定義の前に@classmethodのように書いておくことで、該当メソッドを修飾してくれるもの。

お惚け老人のいい加減な理解では、classmethodは、クラスのインスタンスを生成しなくても呼び出せるクラス共通のメソッドを定義するもの。インスタンスが参照できないので、インスタンス変数は扱えないけれども、クラスに共通(一つ)しかないクラス変数どもの操作は可能。

一方、staticmethodも、クラスのインスタンスを生成しなくても呼び出せるメソッドであります。しかし制約あり、クラス変数にもインスタンス変数にもアクセスできないメソッドみたいです。一般の関数との違いは、クラスの名前空間の中に入れてもらってはいるので、メソッドのお名前が外の人たちと被っても問題ないっと。まあクラスを関数ライブラリの入れ物みたいに使って、ダラダラと沢山関数を詰めて置くときに良いかも。知らんけど。

今回練習のために定義したクラス

いかのこれ見よがしなクラス定義を使って、練習してみようと思います。

class Sample(object):
    count = 0

    def __init__(self, v0):
        self.v0 = v0
        Sample.count += 1

    @classmethod
    def method0(cls, v):
        cls.v = v
        return cls.v

    @classmethod
    def method1(cls):
        return (cls.v, cls.count)

    @classmethod
    def alt_constructor(cls, v0):
        return cls(v0)

    @staticmethod
    def method2(a, b):
        return a + b

    def method3(self):
        return self.v0
クラスメソッドを呼び出してみる

以下では、@classmethodで飾られているmethod0とmethod1を呼び出しています。Pythonのお作法にのっとり、クラスメソッドが第一引数として受け取るのはselfではなく、clsと記してます。ClassMethod0

インスタンスは存在しないので、クラス名. で呼び出せますな。method0では新たなクラス変数を追加したりもしています。method1が返すタプルの値の後の方は、その時点の該当クラスのインスタンス数であります。

スタティックメソッドを呼び出してみる

@staticmethodで飾られているmethod2には、インスタンスメソッドにおけるselfや、クラスメソッドにおける cls のような引数が渡されることがないので、処理は素の関数と似たようなもん?です。呼び出し方だけみるとクラスメソッドと見分けがつきませんが。StaticMethod0

インスタンスをフツーに作成してみる

インスタンスを通常通り、作成してみます。inst0

インスタンスの初期化時に、222という引数を与えているので、インスタンス変数v0には目出度く222が格納されています。

一方、クラスメソッドmethod1を使ってクラス変数を確認してみると、クラス変数countの値が+1されているのが分かります。__init__を通ったってことですな。

クラスメソッドを使ってインスタンスを作成してみる

クラスメソッドとして定義した alt_constructorメソッドは、インスタンスを生成して返すメソッドとして定義されてます。それを使っても新たなインスタンスが生成できますな。inst1

こちらのインスタンス変数 v0 は値555となり、共通のクラス変数 countの値は+1されて2となってます。目論見どおり

Spyderの変数イクスプローラを使って観察

上記後、変数イクスプローラに表示されている変数は以下のように2つ。どちらもSampleクラスのインスタンスを保持するもの。VariableExp

inst0の内部が以下に。inst0Viewer

inst1の内部が以下に。inst1Viewer

まあ、お惚け老人でも、クラスメソッド、スタティックメソッドの使い分けはできるような気がしてきた?ホントか?

ソフトな忘却力(114) Pythonのfunctoolsでラッピングとな? へ戻る

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です