HOWTO · Python
Python の定数
UPPER_CASE 名で Python の定数を定義し、関連する値をまとめ、固定されたメンバーには Enum を使う方法を学びます。
このページの内容
Python には、名前を恒久的に読み取り専用にする const 宣言はありません。通常はモジュールレベルの名前を UPPER_CASE で定義し、再代入をコードレビューで指摘すべき問題として扱います。関連する値をまとめるにはクラスを使い、固定された名前付きメンバーには Enum を使います。
UPPER_CASE 名でモジュール定数を定義する
モジュールやパッケージで共有する値は先頭付近に置き、名前を大文字とアンダースコアで書きます。他のモジュールから通常どおりインポートできます。この規約は意図を示しますが、Python は名前の再束縛を許します。
TIMEOUT_SECONDS = 30
SUPPORTED_FORMATS = ("json", "toml")
print(TIMEOUT_SECONDS)
TIMEOUT_SECONDS = 60 # Legal Python, but a reassignment of a constant by convention.
print(TIMEOUT_SECONDS)
出力:
30
60
タプルはそのオブジェクトの変更を防ぎますが、モジュール名を不変にはしません。SUPPORTED_FORMATS は再束縛できます。リストなどの可変値はその場で変更できます。可能なら不変値を選び、公開設定や API の一部である定数はモジュールに置きます。
関連する値をクラスでまとめる
クラスは Settings.DEFAULT_TIMEOUT のような読みやすい名前空間を提供します。整理には便利ですが、通常のクラス属性は言語が強制する定数ではありません。クラスも通常はそのインスタンスも変更できます。
class Settings:
DEFAULT_TIMEOUT = 30
RETRY_LIMIT = 3
print(Settings.DEFAULT_TIMEOUT)
Settings.DEFAULT_TIMEOUT = 60
print(Settings.DEFAULT_TIMEOUT)
出力:
30
60
カスタムディスクリプターやメタクラスで代入を拒否できますが、複雑さが増し、インスタンス属性、サブクラス化、その他の変更経路にも注意が必要です。明示的でテスト済みの強制要件がなければ、通常のクラスは名前空間として使います。
名前付き値の固定集合には Enum を使う
値を定義済みメンバーに限定する必要がある場合は、標準ライブラリの enum モジュールを使います。Enum メンバーはクラスからアクセスし、新しいメンバー値を代入すると例外が発生します。状態、色、モードなど集合自体に意味がある場合に適しています。
from enum import Enum
class Color(Enum):
RED = "red"
BLUE = "blue"
print(Color.RED.value)
try:
Color.RED = "green"
except AttributeError as error:
print(type(error).__name__)
出力:
red
AttributeError
Enum はすべての値を不変にするものではなく、生の文字列値とも同じではありません。メンバーの同一性が重要なら Color.RED を使い、API が基になる値を要求するなら Color.RED.value を使います。外部入力には Color("red") を使い、未知の値による ValueError を明示的に処理します。
namedtuple と関数を代替手段として検討する
古い collections.namedtuple() では不変フィールドをまとめられます。Constants = namedtuple("Constants", "PI E") に続けて values = Constants(3.14159, 2.71828) とすると、フィールドを代入できないタプルが作られます。ただし values の再束縛は防げず、名前付き選択肢には Enum の方が表現力に優れます。
値を返す関数は構築を隠したり必要時に計算したりできますが、定数宣言ではありません。def api_version(): return "v1" はアクセサーを表します。単純な定数にはモジュール名、整理にはクラス、閉じた集合には Enum を優先してください。
パターンを選び、検証する
通常の共有値には UPPER_CASE のモジュール名、整理にはクラス、固定されたドメイン集合には Enum を使います。変更の境界を明確にしてください。通常の名前とクラス属性は再束縛できますが、Enum メンバーは再代入を拒否します。上の例では正常なアクセスと重要な失敗または再代入を検証しています。軽量な規約を守るにはレビュー、テスト、明確な API も必要です。
まとめ
Python には組み込みの const キーワードがありません。通常の定数はモジュールレベルの UPPER_CASE 名で定義し、関連する定数はクラスでまとめ、名前付きメンバーの固定集合には Enum を選びます。namedtuple() と関数アクセサーは強制的な定数ではなく、用途に応じた代替手段です。