sec04 - Docstringの使い方とメンテナブルなクラス設計【Python入門】
スポンサーリンク

PythonのDocstringとは?コメントとの違いと、メンテナブルなクラス設計のコツ

この回では、クラスやメソッドに説明を書き残す方法であるDocstringを学びます。Docstringを活用すると、自分や他人がクラスの仕様をすぐに理解できるので、メンテナンス性が高まります。また、これまで学んだ内容を総復習し、メンテナブルなクラス設計を体験します。

Docstringとは?Pythonでの使い方と確認方法

Pythonでは、クラスやメソッド、関数の説明をコードに残すことができます。これをDocstringと呼びます。Docstringを書いておくと、IDEの補完機能やhelp()関数でクラスの仕様をすぐに確認できるので、メンテナンス性がぐっと高まります。

例えば、help(list)でlistのDocstringを確認してみましょう。

help(list)
Help on class list in module builtins:

class list(object)
 |  list(iterable=(), /)
 |
 |  Built-in mutable sequence.
 |
 |  If no argument is given, the constructor creates a new empty list.
 |  The argument must be an iterable if specified.
 |
 |  Methods defined here:
 |
 |  __add__(self, value, /)
 |      Return self+value.
.........
 |  append(self, object, /)
 |      Append object to the end of the list.
 |
 |  clear(self, /)
 |      Remove all items from list.
 |
 |  copy(self, /)
 |      Return a shallow copy of the list.
.........

listの各メソッドの情報などを確認することができます。

Docstringの出力の際に、-- More --と表示されることがあります。この表示が出たときは-- More --の後にフォーカスを合わせ、Enterキーを押下して次の行を表示させます。

Docstringとコメントの違い

#は実行時に無視される単なるコメントですが、Docstringはクラスや関数の一部として保持され、help()関数やIDEのツールチップに表示されます。つまり「後で使うための説明文」がDocstringです。

スポンサーリンク

Docstringの書き方:クラスやメソッドへの記述とVSCodeでの確認方法

Docstringはクラスや関数(メソッド)の定義の直後に、トリプルクォーテーション'''で説明文を囲います。説明文では、クラスや関数の概要や、インスタンス変数や引数の情報などを記述します。インデントや改行を揃えると見やすくなります。IDE(VSCode, PyCharmなど)では、補完時にDocstringが表示されるので、誰が読んでも分かりやすくなります。

class Car:
    '''自動車を表現するクラス。

    このクラスは車のブランド・車種・速度・エンジン状態を管理します。
    エンジンの始動/停止、速度の取得と設定などの基本的な操作を提供します。

    Attributes:
        brand (str): 車のブランド名。
        model (str): 車のモデル名。
        _speed (int): 現在の速度(外部から直接アクセス不可)。
        __engine_on (bool): エンジンの状態(True=始動中/False=停止中、非公開属性)。
    '''

    def __init__(self, brand: str, model: str, speed: int = 0):
        '''コンストラクタ。車の初期状態を設定します。

        Args:
            brand (str): ブランド名。
            model (str): 車種名。
            speed (int, optional): 初期速度(デフォルトは 0)。
        '''
        self.brand = brand
        self.model = model
        self._speed = speed
        self.__engine_on = False

クラスのDocstringを確認するには、help(Car)と記述します。

help(Car)

出力例:

class Car(builtins.object)
 |  Car(brand: str, model: str, speed: int = 0)
 |
 |  自動車を表現するクラス。
 |
 |  このクラスは車のブランド・車種・速度・エンジン状態を管理します。
 |  エンジンの始動/停止、速度の取得と設定などの基本的な操作を提供します。
 |
 |  Attributes:
 |      brand (str): 車のブランド名。
 |      model (str): 車のモデル名。
 |      _speed (int): 現在の速度(外部から直接アクセス不可)。
 |      __engine_on (bool): エンジンの状態(True=始動中/False=停止中、非公開属性)。
 |
 |  Methods defined here:
 |
 |  __init__(self, brand: str, model: str, speed: int = 0)
 |      コンストラクタ。車の初期状態を設定します。
 |
 |      Args:
 |          brand (str): ブランド名。
 |          model (str): 車種名。
 |          speed (int, optional): 初期速度(デフォルトは 0)。

Visual Studio Codeでは、クラスやメソッドの入力中に、Docstringの内容が表示されます。

良いクラス設計とは?PythonでのDocstring活用と設計のまとめ

良いクラス設計のポイントは次の通りです。

  • 他人が読んでも理解しやすい
  • 属性やメソッドの意味が明確
  • 内部構造はカプセル化され、外部から安全に扱える
  • 共通処理はメソッド化してコードの重複を避ける
  • Docstringは設計の「目次」として機能する

実践的な振り返り

クラスのセクションの内容をまとめて、1つのクラスを設計してみましょう。以下のポイントを意識します。

  • 属性には___でアクセス制御
  • 取得・設定は@propertyを使う
  • 表示は__str__で分かりやすく
  • Docstringでクラス・メソッド・属性の役割を整理
class Car:
    '''自動車を表現するクラス。

    このクラスは車のブランド・車種・速度・エンジン状態を管理します。
    エンジンの始動/停止、速度の取得と設定などの基本的な操作を提供します。

    Attributes:
        brand (str): 車のブランド名。
        model (str): 車のモデル名。
        _speed (int): 現在の速度(外部から直接アクセス不可)。
        __engine_on (bool): エンジンの状態(True=始動中/False=停止中、非公開属性)。
    '''

    def __init__(self, brand: str, model: str, speed: int = 0):
        '''コンストラクタ。車の初期状態を設定します。

        Args:
            brand (str): ブランド名。
            model (str): 車種名。
            speed (int, optional): 初期速度(デフォルトは 0)。
        '''
        self.brand = brand
        self.model = model
        self._speed = speed
        self.__engine_on = False

    def start_engine(self):
        '''エンジンを始動します。

        エンジン状態を True(ON)に変更します。
        '''
        self.__engine_on = True

    def stop_engine(self):
        '''エンジンを停止します。

        エンジン状態を False(OFF)に変更します。
        '''
        self.__engine_on = False

    @property
    def speed(self) -> int:
        '''現在の速度を取得します。

        Returns:
            int: 現在の速度(km/h)。
        '''
        return self._speed

    @speed.setter
    def speed(self, value: int):
        '''速度を設定します。

        0未満の値が指定された場合はエラーを発生させます。

        Args:
            value (int): 設定する速度(km/h)。

        Raises:
            ValueError: 速度が 0 未満の場合。
        '''
        if value < 0:
            raise ValueError('速度は0以上でなければなりません。')
        self._speed = value

    def __str__(self) -> str:
        '''オブジェクトの文字列表現を返します。

        Returns:
            str: 車のブランド・モデル・速度・エンジン状態を含む文字列。
        '''
        return (
            f'{self.brand} {self.model}'
            f"(速度: {self._speed}km/h, エンジン: {'ON' if self.__engine_on else 'OFF'})"
        )

print()help()の結果を確認してみましょう。

car = Car('Toyota', 'Corolla', 50)
print(car)
help(car)
Toyota Corolla(速度: 50km/h, エンジン: OFF)
Help on Car in module __main__ object:

class Car(builtins.object)
 |  Car(brand: str, model: str, speed: int = 0)
 |
 |  自動車を表現するクラス。
 |
 |  このクラスは車のブランド・車種・速度・エンジン状態を管理します。
 |  エンジンの始動/停止、速度の取得と設定などの基本的な操作を提供します。
 |
 |  Attributes:
 |      brand (str): 車のブランド名。
 |      model (str): 車のモデル名。
 |      _speed (int): 現在の速度(外部から直接アクセス不可)。
 |      __engine_on (bool): エンジンの状態(True=始動中/False=停止中、非公開属性)。
 |
 |  Methods defined here:
 |
 |  __init__(self, brand: str, model: str, speed: int = 0)
 |      コンストラクタ。車の初期状態を設定します。
 |
 |      Args:
 |          brand (str): ブランド名。
 |          model (str): 車種名。
 |          speed (int, optional): 初期速度(デフォルトは 0)。
 |
 |  __str__(self) -> str
 |      オブジェクトの文字列表現を返します。
 |
 |      Returns:
 |          str: 車のブランド・モデル・速度・エンジン状態を含む文字列。
 |
 |  start_engine(self)
 |      エンジンを始動します。
 |
 |      エンジン状態を True(ON)に変更します。
 |
 |  stop_engine(self)
 |      エンジンを停止します。
 |
 |      エンジン状態を False(OFF)に変更します。
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables
 |
 |  __weakref__
 |      list of weak references to the object
 |
 |  speed
 |      現在の速度を取得します。
 |
 |      Returns:
 |          int: 現在の速度(km/h)。
条件演算子について

上記コードの、__str__メソッドの返り値として渡すフォーマット文字列の中に'ON' if self.__engine_on else 'OFF'という記述があります。この書き方は、Pythonでよく使われる「条件演算子(条件式)」と呼ばれる構文です。一見むずかしそうに見えますが、実は「1行で書けるif文」です。

基本の書式

値_if_true if 条件 else 値_if_false

日本語にすると、次のような意味になります。

「もし条件Trueなら値_if_trueを使い、そうでなければ値_if_falseを使う」

具体的な例

'ON' if self.__engine_on else 'OFF'

このコードは次のように読めます。

「もしself.__engine_onTrueなら'ON'、そうでなければ'OFF'を返す」

普通のif文で書くとこうなります:

if self.__engine_on:
    status = 'ON'
else:
    status = 'OFF'

1行でスッキリ書いたのが、次のような書き方です。

status = 'ON' if self.__engine_on else 'OFF'

使いどころ:

  • 短い条件分岐を1行で書きたいとき
  • 変数に代入する内容が「条件で分かれる」だけのとき

もう一つの例

age = 20
message = '成人です' if age >= 18 else '未成年です'
print(message)

出力結果:

成人です
スポンサーリンク