Pythonを学んでいると、__init__ や __name__ のように「アンダースコアが2つずつついた名前(__〇〇__)」に出会います。
これらは「ダンダ(Dunder)」とも呼ばれ、Pythonにおいて特別な意味を持つマジックメソッドや特殊変数です。
最初はこんなふうに思ったことはありませんか?
- なんでアンダースコアが2つも?
- これはいつ使うの?
本記事では、Pythonで頻出する“ダンダ(__〇〇__)”について、わかりやすく解説します。
ダンダ(__〇〇__)とは?
「ダンダ(dunder)」は “double underscore” の略語で、
__name__ や __init__ のように「前後をアンダースコア2つで囲まれた名前」のことを指します。
Pythonでは、この形式の名前は特別な意味や役割を持ち、主に以下の3種類に分類できます:
-
マジックメソッド(特殊メソッド)
例:__init__,__str__,__len__,__getitem__ -
特殊変数(ビルトイン変数)
例:__name__,__file__,__doc__ -
その他(構文では使わない内部的な名前)
例:__pycache__,__init__.py,__main__(後述)
1. よく使うマジックメソッド(特殊メソッド)
・ __init__ :インスタンスの初期化(コンストラクタ)
クラスからインスタンスを生成するときに自動で呼ばれるメソッドです。
主にインスタンス変数の初期化に使われます。
class User:
def __init__(self, name):
self.name = name
def say_hello(self):
return f"Hello, {self.name}"
user = User("Taro")
print(user.say_hello()) # Hello, Taro
・ __str__ / __repr__ :文字列表現の制御
print() 関数などでオブジェクトを表示したときに、どのように文字列として出力されるかを定義できます。
__str__ は人間向け、__repr__ は開発者向けの表現に使われることが多いです。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Point({self.x}, {self.y})"
p = Point(1, 2)
print(p) # Point(1, 2)
・ __len__ :長さの取得
組み込み関数 len() を呼んだときに実行されるメソッドです。
リストのような「長さを持つクラス」にこのメソッドを実装することで、len(obj) が使えるようになります。
class MyList:
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
items = MyList([1, 2, 3])
print(len(items)) # 3
・ __getitem__ / __setitem__ :インデックスアクセス
リストや辞書のように obj[key] 形式で要素を取得・代入できるようにするメソッドです。
カスタムクラスにリスト的な動作を持たせたいときに使われます。
class MyDict:
def __init__(self):
self.store = {}
def __getitem__(self, key):
return self.store.get(key, None)
def __setitem__(self, key, value):
self.store[key] = value
d = MyDict()
d["a"] = 100
print(d["a"]) # 100
2. よく使う特殊変数(ビルトイン変数)
・ __name__ :現在のスクリプトの実行モードを示す
スクリプトが「直接実行された」のか「importされた」のかを判定するための変数です。
直接実行時は "__main__" が入ります。
例1:2ファイル構成で確認
# submodule.py
print("__name__ in submodule.py:", __name__)
# main.py
import submodule
print("__name__ in main.py:", __name__)
実行結果(main.pyを実行):
__name__ in submodule.py: submodule
__name__ in main.py: __main__
例2:__name__ == "__main__" の使い方
def main():
print("これはメイン処理です")
if __name__ == "__main__":
main()
・ __file__ :ファイルのパス情報を持つ
スクリプトファイルの絶対パス(または相対パス)を表す変数です。
デバッグや設定ファイルの読込パスを取得するときに使われます。
print(__file__) # 現在のファイルの絶対パス
・ __doc__ :ドキュメンテーション文字列
関数やクラスに記述されたdocstring(説明文)を取得するための変数です。
help() 関数や開発ドキュメントにも使われます。
def greet():
"""挨拶をする関数"""
return "Hello"
print(greet.__doc__) # 挨拶をする関数
3. その他
・ __main__ とは?
__main__ は、__name__ に格納される文字列で、「このファイルが直接実行された」ことを意味します。
__name__ == "__main__" の形で実行判定に使われるのが一般的です。
if __name__ == "__main__":
main()
・ __pycache__ は構文上のダンダではない
__pycache__ は、Pythonが .py ファイルを実行したときに自動生成するキャッシュ用フォルダです。
コード内で使用することはなく、実行速度向上のために .pyc ファイルが保存されます。
・ __init__.py とは?
__init__.py は、ディレクトリを「Pythonパッケージ」として認識させるための初期化ファイルです。
中身は空でもよく、共通関数や初期化処理を書くこともできます。
例:
mypackage/
├── __init__.py
└── module.py
# 呼び出し側
import mypackage.module
まとめ
-
__〇〇__は「ダンダ(dunder)」と呼ばれ、Pythonにおいて特別な意味を持つ名前 -
ダンダには主に3種類ある:
- マジックメソッド(例:
__init__,__str__) - 特殊変数(例:
__name__,__file__,__doc__) - その他(構文では使わない内部名:
__pycache__,__init__.py,__main__)
- マジックメソッド(例:
-
__name__ == "__main__"はスクリプトの実行制御に使える重要な仕組み -
見た目が似ていても、使い方や意味が全く異なるものがあるので注意!
最初はちょっととっつきにくいかもしれませんが、
実際にコードを書きながら出会ったタイミングで「これはどういう意味だったかな?」と立ち返ることで、少しずつ身についていくと感じました。
ダンダ系の要素は奥が深いですが、ひとつずつ整理しながら理解していきたいと思います。