本当に誰でも読める!! Pythonソースコードの読み方講座(第2回) class にまつわるコードの読み方

  • HOME
  • 本当に誰でも読める!! Pythonソースコードの読み方講座(第2回) class にまつわるコードの読み方

本記事は当社が発行しているシミュレーションメールマガジンVol.2の記事です。
シミュレーションメールマガジンの詳細・購読申込はこちら のサポートページから

本当に誰でも読める!! Python の class にまつわるコードの読み方

S4 Simulation System はGUI操作でシミュレーションモデルを構築できることが魅力ですが、ユーザ側でもPythonコードを読み書きできることで実現できるシミュレーションの幅が大きく広がります。

ノン・プログラマーの方に向けて、Python の「ソースコードの読み方」を解説している本講座ですが、前回は、Pythonスクリプトを構成する要素(単語(変数=オブジェクト)と ( ) や"." ":" "[ ]" などの記号)を紹介し、それぞれの「読み方」を紹介しました。 2回目の今回はもう少し踏み込んで、Python で重要な概念である「class(クラス)」に関わるソースコードについて、その読み方を紹介したいと思います。 Python に慣れていらっしゃらない方で、第1回をまだお読みになられていない方はこちらを先にご覧いただくことをお薦めいたします。

例文

さて、今回の例文は以下です(S4 のエージェントシミュレーションを行うときに生成されるソースコードの一部になります)

class _Agent (SFMAgentBase):
    def initAfter(self, *args, **keys):
        """エージェント初期化後に呼ばれる。"""
        pass
    def step(self):
        """エージェントのステップ処理を記述する。SFM に従った基本的な動作を行った後に呼ばれる。"""
        if self.isStopping(): # エージェントが停止状態(目的地に到着)
            # エージェントを削除する:
            self.agentset.remove(self)
        elif self.isInErrorState(): # エラーが発生(目的地に到達不可など)
            print((self.state.message))
            # エージェントを削除する:
            self.agentset.remove(self)
        else: # それ以外の場合は、目的地に移動中
            pass


例によってこの時点で理解できなくて全く問題ありません! 前回には登場しなかった要素として、次のようなものがありますね:

  • キーワード "pass"、"print"
  • キーワード "class"
  • キーワード "def" から始まる行
  • 何度か現れる "self" という単語

これらのうち、"pass"、"print" については前回の応用で、そのままで読むことができます。それぞれ「何もしない」「(画面に)表示する」という意味になります(わざわざ「何もしない」を意味するキーワードが用意されているのも不思議ですが、これがあるとコーディングで便利なのです)。 残りの3つはすべて「クラス」というものに関わる内容になっています。

全体像

上のコードを翻訳すると、以下のようになります:

class クラス名 (継承先):
    def メソッド名1(self, 引数):
        """コメント"""
        # 処理1
    def メソッド名2(self):
        """コメント"""
        # 処理2


これは Python の「クラス定義」を行うコードの構文になっています。
ざっくりいうと

(クラス名)というクラスで、(メソッド名1)というメソッド(引数は self や~をとる)と(メソッド名2)というメソッド(引数は self のみ)を持っているものを定義する

という読み方になります。
以下、「クラス」「メソッド」という言葉のいみやキーワード class、def、self についてもう少し詳しく見ていきましょう。

"class" による「クラス」定義

改めて、まずはコードの1行目を見てみます:

class _Agent (SFMAgentBase):


ここでは "class" キーワードを用いて「クラス」定義を行っています。 「クラス」というのは色々な属性(内部状態)とメソッド(操作)をひとつにまとめたもので、Pythonプログラミングの根幹を成します。 第1回の記事で

Python ではすべて「オブジェクト」というモノが動いている

という話をしましたが、この「モノ」がクラス(正確には、定義したクラスを実体化したもの)に相当します。

S4(psim)においてもエージェントシミュレーションのエージェントや環境、離散イベントシミュレーションのファシリティやストア、データを記録するモニタなど、全てクラスを使って記述しています。
使うには若干の慣れが必要ですが、使ったことが無くてもソースコードを「読む」ことはできます

class A (B):


B という既存のクラスを継承して A というクラスを作る

と読めばよいです。
「継承」とは既存のクラスを拡張する、という程度の理解で大丈夫です。S4 を使う場合、ご自身で一からクラスを定義することは基本的には無く、GUI部品内のエディタでコード編集することでクラスのメソッドの中身を作り込んだり、カスタムコードから新しくメソッドを作ったり、という使い方をすることが多いです。

さて、この1行だけでは名前をつける以上のことはしていないので、次のメソッド定義によってクラスに意味を与えていくことになります。

"def" による「メソッド」定義~"self" の意味と使い方

    def initAfter(self, *args, **keys):
        """エージェント初期化後に呼ばれる。"""
        pass
    def step(self):
        """エージェントのステップ処理を記述する。SFM に従った基本的な動作を行った後に呼ばれる。""" 
        if self.isStopping(): # エージェントが停止状態(目的地に到着)
            # エージェントを削除する:
            self.agentset.remove(self)
        elif self.isInErrorState(): # エラーが発生(目的地に到達不可など)
            print((self.state.message))
            # エージェントを削除する:
            self.agentset.remove(self)
        else: # それ以外の場合は、目的地に移動中
            pass


"def"キーワードを用いてメソッド定義を行っています。
メソッド、というのは一連の処理をひとつにまとめて名前をつけたもののことで、ここでは_Agentクラスに initAfter という名前のメソッドと、step という名前のメソッドを定義しています。
メソッドは呼ぶときに変数を与えることができ、「何に対して処理を行うか」を指定することができます。

def M(self, a, b):


と書くことで

M という名前で、引数として(self に加えて)a,bをとるメソッドを作る

のように読みます。
コード例では

def initAfter(self, *args, **keys):


のように書かれており、引数が少し複雑に見えます。この中で重要なのは最初の "self" で、残りの args, *keys は今回は気にしなくて良いです(可変長引数というもので、しばしばこういう書き方をすることがある、という程度で大丈夫です)。

さて、"self" はクラスでメソッドを定義する際に最初に与えられるもので、クラスを使う/作る際に重要な役割を果たします。
上記のstepメソッドにおいては

self.isStopping()
self.agentset.remove(self)



といった形でこの引数selfが使われていますが、"self" は読み方としては「自分自身」のように解釈すればよいです。ですのでこれらの文は

自分自身のisStoppingメソッドを実行している 自分自身の agentset というモノの、remove というメソッドに対して引数として self を与えて実行している

のように読むことができます。
(ピリオド.でつなげるとそのモノの「所有物」にアクセスできて、カッコ()をつけるとそれに仕事をさせる、というのは前回の内容でしたね。)

ここは_Agentクラスの定義の中なので、ここでいう self は_Agentクラスにおける「自分自身」、すなわち(エージェントシミュレーションでいうところの)エージェント、ということになります。
また、self.isStopping() というメソッドは_Agentクラスのメソッドということになります。

(が、今回のコードの中にはisStoppingメソッドの定義はありません。それがどこにあるかというと最初に現れた「継承」先であるSFMAgentBaseクラスになります。これは psim が提供しているクラスなので、S4 のソースコードの中に存在しています。)

少々説明が長くなってしまいましたが、重要なのは

1. クラスにメソッドを定義する際は基本的に最初の引数は self にする
2. この self を経由して自分自身や継承先のクラスのメソッド(↑の isStopping)や属性(↑の self.agentset)にアクセスすることができる

ということになります。
特に S4 でコーディングを行う場合は2の使い方を頻繁に行うことになります
デフォルトで入っているコードにも頻繁に self が現れますし、コード編集で self.~~ として必要な機能を呼び出すことも基本的な使い方になります(どのようなメソッドが用意されているかは、サンプルコードや言語リファレンスを参照することで調べることができます)。

注意として、self の意味はそれが使われているクラスに従って読み替える必要があります。S4 ですとそのメソッドがエージェントなのか、エージェント集合なのか、環境なのかに応じて self の指すものが変わりますので注意しながらコードを読むようにしてください。

補足

"def"キーワードは必ずしもクラス定義の中でしか使えないわけではなく、外に書くことも可能です。この場合は特定のクラスとは結びつかないので引数の最初を self にする必要はなく、単に一連の処理をまとめたもの(「関数」)として扱われることになります。

おわりに

今回は Python のクラス定義に関するコードの読み方を解説しました。 S4 の psim に限らず、Python は非常に豊富なライブラリが提供されています。今後プログラミングをより本格的に始め、これらを使う際には今回の内容を抑えておくだけでも理解しやすくなるのではないでしょうか。

豊岡 祥 株式会社 NTTデータ数理システム シミュレーション&マイニング部所属。
S4 Simulation System の開発のほか、機械学習・シミュレーション・数理最適化を幅広く扱い、分野を横断した問題解決に取り組んでいる。
入社後に競技プログラミングをはじめ、PGBATTLE2023にて企業の部団体3位入賞。

著書: 「XAI(説明可能なAI)──そのとき人工知能はどう考えたのか?」リックテレコム
趣味: 合唱
「数理科学の基礎知識」e-book無料ダウンロードはこちら