Pythonの特殊メソッドは、クラスに「Pythonらしいふるまい」を与えるための強力な仕組みです。
演算子オーバーロードやコンテナのような挙動、コンテキストマネージャなど、多くの標準機能は特殊メソッドで支えられています。
本記事では主な特殊メソッドを一覧形式で整理しつつ、実際のクラス設計に役立つ書き方とパターンを詳しく解説します。
Pythonの特殊メソッドとは
特殊メソッド(dunderメソッド)の基本と役割

Pythonの特殊メソッドとは、名前が__xxx__のように両端をアンダースコアで囲まれたメソッドのことです。
ダブルアンダースコアからdunderメソッドとも呼ばれます。
これらは演算子や組み込み関数、構文が実行されたときに自動的に呼び出されるフックとして機能します。
例えば、次のような関係があります。
a + b→a.__add__(b)len(x)→x.__len__()with obj:→obj.__enter__()とobj.__exit__()
開発者は通常__len__や__enter__を直接呼び出すことは少なく、Pythonの構文を使うだけで自動的に特殊メソッドが呼ばれるという形になります。
特殊メソッドを使うメリット

特殊メソッドを活用する最大のメリットは、自作クラスを標準ライブラリと同じ感覚で扱えるようになることです。
例えば、数値風のクラスに__add__を実装しておけばa + bという自然な形で扱えますし、コレクション風のクラスに__len__と__iter__を実装すればlen(x)やfor item in x:がそのまま使えます。
また__repr__や__str__を適切に定義することでデバッグ時に読みやすい出力が得られ、__enter__や__exit__を使うことでリソース管理のミスを減らせます。
オブジェクトの生成と文字列表現の特殊メソッド一覧
__new__と__init__

__new__と__init__は、オブジェクト生成時に使われるペアです。
__new__(cls, ...)
クラスから実際のインスタンスを作るクラスメソッド(実際は静的メソッドとして定義)です。必ずインスタンスを返す必要があります。主にイミュータブルな型(数値、文字列など)を継承するときにカスタマイズします。__init__(self, ...)
生成されたインスタンスを初期化するためのメソッドです。戻り値は必ずNoneでなければなりません。
__new__と__init__の基本実装例
class MyNumber(int):
# インスタンス生成前に値を加工したい場合の例
def __new__(cls, value):
# ここでは負の値を絶対値に変換してからintを生成する
obj = super().__new__(cls, abs(value))
return obj
def __init__(self, value):
# __new__で実際に格納された値はすでにabs(value)
# ここではログ出力や追加属性の設定だけを行う
self.original_value = value
n = MyNumber(-10)
print(n) # __str__はintのものが使われる
print(n.original_value)
10
-10
__new__を意識すべきケース
通常のクラス設計では__init__だけで十分ですが、イミュータブルな組み込み型を継承するときやシングルトンのような生成制御を行うときには__new__を使います。
__del__

__del__(self)は、オブジェクトがガベージコレクションで破棄されるときに呼ばれる「デストラクタ」のようなメソッドです。
ただし呼ばれるタイミングは保証されず、プロセス終了時には呼ばれないこともあるため、重要なリソース解放の手段としては推奨されません。
class Tracked:
def __init__(self, name):
self.name = name
print(f"[INIT] {self.name}")
def __del__(self):
# ここで重要な処理をしてはいけない(呼ばれない場合がある)
print(f"[DEL] {self.name}")
def create():
obj = Tracked("temp")
create()
print("関数終了")
[INIT] temp
関数終了
[DEL] temp
実際にはインタプリタの実装や参照サイクルの有無などで挙動が変わるため、ファイルやネットワークリソースの解放にはwith文と__enter__/__exit__を使うのが安全です。
__str__と__repr__

__str__と__repr__は、オブジェクトの文字列表現を制御します。
__str__(self)
人間が読むことを前提とした、わかりやすい文字列を返します。print(obj)やstr(obj)で使われます。__repr__(self)
開発者向けの詳細な表現で、可能ならeval(repr(obj)) == objが成り立つように記述するのが理想とされています。REPLで変数を評価したときやrepr(obj)で使われます。
実務では__repr__をしっかり作り、__str__は__repr__を流用することも多いです。
class User:
def __init__(self, user_id, name, is_admin=False):
self.user_id = user_id
self.name = name
self.is_admin = is_admin
def __repr__(self):
# 開発者が状態を一目で確認できるように詳細に書く
return (f"User(user_id={self.user_id!r}, "
f"name={self.name!r}, is_admin={self.is_admin!r})")
def __str__(self):
# ユーザ向けにはコンパクトな表現
role = "admin" if self.is_admin else "user"
return f"{self.name} ({role})"
u = User(1, "Alice", True)
print(u) # __str__
print(repr(u)) # __repr__
Alice (admin)
User(user_id=1, name='Alice', is_admin=True)
__format__

__format__(self, format_spec)はformat(obj, spec)やf"{obj:spec}"のときに呼ばれます。
独自クラスにカスタム書式指定を提供したい場合に使います。
from datetime import datetime
class LogRecord:
def __init__(self, level, message, created=None):
self.level = level
self.message = message
self.created = created or datetime.now()
def __format__(self, format_spec):
# format_specに応じて出力を切り替える例
if format_spec == "short":
return f"[{self.level}] {self.message}"
elif format_spec == "time":
ts = self.created.strftime("%H:%M:%S")
return f"{ts} | {self.level} | {self.message}"
else:
# デフォルトの詳細形式
ts = self.created.isoformat(timespec="seconds")
return f"{ts} [{self.level}] {self.message}"
rec = LogRecord("INFO", "system started")
print(f"{rec:short}")
print(f"{rec:time}")
print(f"{rec}")
[INFO] system started
12:34:56 | INFO | system started
2025-12-17T12:34:56 [INFO] system started
__bytes__
__bytes__(self)はbytes(obj)が呼ばれたときに使われるメソッドで、オブジェクトをバイト列にシリアライズするときの標準的なフックとして利用できます。
class Packet:
def __init__(self, msg_type, payload: bytes):
self.msg_type = msg_type
self.payload = payload
def __bytes__(self):
# 単純なプロトコル: [type(1byte)][len(2byte)][payload]
length = len(self.payload)
header = bytes([self.msg_type]) + length.to_bytes(2, "big")
return header + self.payload
p = Packet(1, b"hello")
raw = bytes(p)
print(raw)
b'\x01\x00\x05hello'
演算子オーバーロードの特殊メソッド一覧
算術演算子の特殊メソッド

代表的な算術演算子と特殊メソッドの対応は次のとおりです。
| 演算子 | メソッド | 説明 |
|---|---|---|
| + | __add__ | 加算 |
| – | __sub__ | 減算 |
| * | __mul__ | 乗算 |
| / | __truediv__ | 真の除算(浮動小数) |
| // | __floordiv__ | 切り捨て除算 |
| % | __mod__ | 剰余 |
| ** | __pow__ | べき乗 |
| -x | __neg__ | 単項マイナス |
| +x | __pos__ | 単項プラス |
| abs(x) | __abs__ | 絶対値 |
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
# 型チェックを行い、不正な型にはNotImplementedを返すのが慣習
if not isinstance(other, Vector2D):
return NotImplemented
return Vector2D(self.x + other.x, self.y + other.y)
def __sub__(self, other):
if not isinstance(other, Vector2D):
return NotImplemented
return Vector2D(self.x - other.x, self.y - other.y)
def __neg__(self):
return Vector2D(-self.x, -self.y)
def __abs__(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
def __repr__(self):
return f"Vector2D({self.x}, {self.y})"
v1 = Vector2D(1, 2)
v2 = Vector2D(3, 4)
print(v1 + v2)
print(v1 - v2)
print(-v1)
print(abs(v2))
Vector2D(4, 6)
Vector2D(-2, -2)
Vector2D(-1, -2)
5.0
右辺演算・インプレース演算の特殊メソッド

右辺演算とインプレース演算には次のようなメソッドがあります。
| 種類 | 通常 | 右辺 | インプレース |
|---|---|---|---|
| 加算 | __add__ | __radd__ | __iadd__ |
| 減算 | __sub__ | __rsub__ | __isub__ |
| 乗算 | __mul__ | __rmul__ | __imul__ |
| 真の除算 | __truediv__ | __rtruediv__ | __itruediv__ |
| べき乗 | __pow__ | __rpow__ | __ipow__ |
| など | … | … | … |
__radd__(self, other)などの右辺演算メソッドは、左辺の__add__がNotImplementedを返したときに呼ばれます。__iadd__(self, other)などのインプレース演算メソッドはa += bのときに優先的に呼ばれ、可能なら自分自身を変更して返す実装にします。
class NumberBox:
def __init__(self, value):
self.value = value
def __add__(self, other):
if isinstance(other, NumberBox):
return NumberBox(self.value + other.value)
if isinstance(other, (int, float)):
return NumberBox(self.value + other)
return NotImplemented
def __radd__(self, other):
# 右辺加算: int + NumberBoxなど
return self.__add__(other)
def __iadd__(self, other):
# インプレース: 自分を直接書き換える
if isinstance(other, NumberBox):
self.value += other.value
elif isinstance(other, (int, float)):
self.value += other
else:
return NotImplemented
return self
def __repr__(self):
return f"NumberBox({self.value})"
nb = NumberBox(10)
print(5 + nb) # __radd__
nb += 3 # __iadd__
print(nb)
NumberBox(15)
NumberBox(13)
比較演算子の特殊メソッド

比較演算子には次のメソッドがあります。
| 演算子 | メソッド | 説明 |
|---|---|---|
| == | __eq__ | 等価 |
| != | __ne__ | 非等価 |
| < | __lt__ | より小さい |
| <= | __le__ | 以下 |
| > | __gt__ | より大きい |
| >= | __ge__ | 以上 |
ソート可能なオブジェクトにしたい場合は、少なくとも__lt__と__eq__を実装します。
class Version:
def __init__(self, major, minor):
self.major = major
self.minor = minor
def _key(self):
return (self.major, self.minor)
def __eq__(self, other):
if not isinstance(other, Version):
return NotImplemented
return self._key() == other._key()
def __lt__(self, other):
if not isinstance(other, Version):
return NotImplemented
return self._key() < other._key()
def __repr__(self):
return f"{self.major}.{self.minor}"
versions = [Version(1, 2), Version(1, 10), Version(1, 3)]
print(sorted(versions))
print(Version(1, 2) < Version(1, 3))
[1.2, 1.3, 1.10]
True
ビット演算子の特殊メソッド
ビット演算にも対応する特殊メソッドがあります。
フラグ集合やビットマスクをラップするクラスで使われることが多いです。
| 演算子 | メソッド | 説明 |
|---|---|---|
| & | __and__ | ビットAND |
| | | __or__ | ビットOR |
| ^ | __xor__ | 排他的OR |
| ~x | __invert__ | ビット反転 |
| << | __lshift__ | 左シフト |
| >> | __rshift__ | 右シフト |
__bool__
__bool__(self)はbool(obj)やif obj:のときに呼ばれ、オブジェクトの真偽値を決める役割を持ちます。
未定義の場合は__len__が代わりに参照され、長さ0がFalse、それ以外がTrueになります。
class Config:
def __init__(self, options):
self.options = options
def __bool__(self):
# 有効なオプションが1つ以上あればTrueとみなす
return bool(self.options)
cfg = Config({})
if not cfg:
print("設定が空です")
設定が空です
コンテナ・イテレータ関連の特殊メソッド一覧
__len__と__contains__

class TagSet:
def __init__(self, *tags):
self._tags = set(tags)
def __len__(self):
return len(self._tags)
def __contains__(self, item):
# 大文字小文字を区別しないタグ集合とする例
return item.lower() in {t.lower() for t in self._tags}
tags = TagSet("Python", "Django")
print(len(tags))
print("python" in tags)
2
True
__getitem__と__setitem__と__delitem__
__getitem__(self, key)はobj[key]で呼ばれ、__setitem__(self, key, value)はobj[key] = value、__delitem__(self, key)はdel obj[key]で呼ばれます。
class Settings:
def __init__(self):
self._data = {}
def __getitem__(self, key):
# 存在しないときにわかりやすいエラーを出す
try:
return self._data[key]
except KeyError:
raise KeyError(f"設定キーがありません: {key!r}")
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
s = Settings()
s["timeout"] = 30
print(s["timeout"])
del s["timeout"]
30
スライス操作用の特殊メソッド

スライスは専用のメソッドがあるわけではなく、__getitem__などにsliceオブジェクトが渡されます。
class RangeView:
def __init__(self, data):
self._data = list(data)
def __getitem__(self, index):
if isinstance(index, slice):
# スライス用の処理
return RangeView(self._data[index])
else:
return self._data[index]
def __len__(self):
return len(self._data)
def __repr__(self):
return f"RangeView({self._data!r})"
rv = RangeView(range(10))
print(rv[2])
print(rv[2:6])
2
RangeView([2, 3, 4, 5])
__iter__と__next__

class Countdown:
def __init__(self, start):
self.current = start
def __iter__(self):
# 自分自身がイテレータでもあるケース
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
value = self.current
self.current -= 1
return value
for i in Countdown(3):
print(i)
3
2
1
__reversed__
__reversed__(self)はreversed(obj)で呼ばれます。
未定義の場合、__len__と__getitem__で逆順にアクセスしようとしますが、効率的な逆順イテレータを提供したい場合は明示的に実装します。
class History:
def __init__(self):
self._events = []
def add(self, event):
self._events.append(event)
def __iter__(self):
return iter(self._events)
def __reversed__(self):
return reversed(self._events)
h = History()
h.add("start")
h.add("process")
h.add("end")
print(list(h))
print(list(reversed(h)))
['start', 'process', 'end']
['end', 'process', 'start']
__missing__
__missing__(self, key)はdictサブクラス専用のフックで、存在しないキーを参照したときに呼ばれます。
class DefaultDict(dict):
def __init__(self, default_factory, *args, **kwargs):
super().__init__(*args, **kwargs)
self.default_factory = default_factory
def __missing__(self, key):
value = self.default_factory()
# 自動的に登録しておく
self[key] = value
return value
d = DefaultDict(list)
d["errors"].append("first error")
print(d)
{'errors': ['first error']}
属性アクセス・コンテキスト管理の特殊メソッド一覧
__getattr__と__getattribute__

class LazyAttrs:
def __init__(self):
self._cache = {}
def __getattr__(self, name):
# 存在しない属性にアクセスされたときだけ呼ばれる
if name == "expensive":
print("計算中...")
value = sum(range(10_000))
self._cache[name] = value
return value
raise AttributeError(name)
def __getattribute__(self, name):
# すべてのアクセスを横取り
if name == "_cache":
# 無限再帰を避けるためsuperを使う
return super().__getattribute__(name)
if name in super().__getattribute__("_cache"):
return self._cache[name]
return super().__getattribute__(name)
obj = LazyAttrs()
print(obj.expensive) # 初回は計算
print(obj.expensive) # 2回目以降はキャッシュから
計算中...
49995000
49995000
__getattribute__は強力ですが、実装を誤ると無限再帰になりやすいため、必要な場合だけ慎重に使うべきです。
__setattr__と__delattr__
__setattr__(self, name, value)はobj.name = valueで呼ばれます。__delattr__(self, name)はdel obj.nameで呼ばれます。
class ReadOnlyOnce:
def __init__(self):
super().__setattr__("_locked", False)
def __setattr__(self, name, value):
if name == "value" and getattr(self, "_locked", False):
raise AttributeError("valueは一度しか設定できません")
super().__setattr__(name, value)
if name == "value":
super().__setattr__("_locked", True)
obj = ReadOnlyOnce()
obj.value = 10
print(obj.value)
# 次は例外
# obj.value = 20
10
__dir__
__dir__(self)はdir(obj)で呼ばれ、インタラクティブシェルでの補完候補などを制御できます。
class PublicAPI:
def __init__(self):
self._internal = 1
self.visible = 2
def __dir__(self):
# 公開したい属性だけを返す
return ["visible"]
p = PublicAPI()
print(dir(p))
['visible']
__enter__と__exit__

__enter__(self)と__exit__(self, exc_type, exc, tb)は、コンテキストマネージャを実装するためのメソッドです。
class FileLogger:
def __init__(self, path):
self.path = path
self._f = None
def __enter__(self):
self._f = open(self.path, "a", encoding="utf-8")
self._f.write("=== start ===\n")
return self
def __exit__(self, exc_type, exc, tb):
if exc:
self._f.write(f"ERROR: {exc}\n")
self._f.write("=== end ===\n")
self._f.close()
# 例外を抑制しない場合はFalseを返す
return False
def log(self, msg):
self._f.write(msg + "\n")
with FileLogger("log.txt") as logger:
logger.log("hello")
# log.txt の中身(例)
=== start ===
hello
=== end ===
デスクリプタプロトコル

デスクリプタは、属性アクセスの振る舞いをクラス属性側に委ねる仕組みです。
次の3つのメソッドから構成されます。
__get__(self, instance, owner)__set__(self, instance, value)__delete__(self, instance)
class Typed:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, instance, owner):
if instance is None:
return self # クラスからアクセスされた場合
return instance.__dict__.get(self.name)
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"{self.name} must be {self.expected_type}")
instance.__dict__[self.name] = value
class Person:
age = Typed("age", int)
def __init__(self, age):
self.age = age
p = Person(20)
print(p.age)
# p.age = "old" # TypeError
20
propertyも内部的にはデスクリプタであり、@propertyで作られたオブジェクトは__get__/__set__を持っています。
クラス・インスタンス挙動を変える特殊メソッド一覧
__call__
__call__(self, ...)を実装すると、インスタンスを関数のように呼び出せるようになります。
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, x):
return x * self.factor
double = Multiplier(2)
print(double(10))
20
__instancecheck__と__subclasscheck__

これらは主に抽象基底クラス(ABC)で使われ、isinstanceやissubclassの挙動をカスタマイズします。
通常はabc.ABCMetaを使うため、直接実装する機会は多くありません。
メタクラス関連の特殊メソッド

メタクラスは「クラスを生成するクラス」です。
メタクラス側で次のような特殊メソッドを実装できます。
__new__(mcls, name, bases, namespace)
クラスオブジェクト生成の前処理。__init__(cls, name, bases, namespace)
クラスオブジェクトの初期化。__call__(cls, *args, **kwargs)
クラス呼び出し時(インスタンス生成)の挙動をカスタマイズ。
class RegistryMeta(type):
registry = {}
def __new__(mcls, name, bases, namespace):
cls = super().__new__(mcls, name, bases, namespace)
if name != "Base":
RegistryMeta.registry[name] = cls
return cls
class Base(metaclass=RegistryMeta):
pass
class ServiceA(Base):
pass
class ServiceB(Base):
pass
print(RegistryMeta.registry)
{'ServiceA': <class '__main__.ServiceA'>, 'ServiceB': <class '__main__.ServiceB'>}
Python特殊メソッドの実用パターン集
数値クラス・ベクトルクラスでの演算子オーバーロード例

class Vec2:
def __init__(self, x, y):
self.x = x
self.y = y
def _pair(self):
return (self.x, self.y)
def __add__(self, other):
if not isinstance(other, Vec2):
return NotImplemented
return Vec2(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
if not isinstance(scalar, (int, float)):
return NotImplemented
return Vec2(self.x * scalar, self.y * scalar)
def __rmul__(self, scalar):
return self.__mul__(scalar)
def __abs__(self):
x, y = self._pair()
return (x * x + y * y) ** 0.5
def __repr__(self):
return f"Vec2({self.x}, {self.y})"
v1 = Vec2(1, 2)
v2 = Vec2(3, 4)
print(v1 + v2)
print(2 * v1)
print(abs(v2))
Vec2(4, 6)
Vec2(2, 4)
5.0
設定オブジェクト・DTOへの__repr__活用例

class AppConfig:
def __init__(self, host, port, debug=False):
self.host = host
self.port = port
self.debug = debug
def __repr__(self):
return (f"AppConfig(host={self.host!r}, "
f"port={self.port!r}, debug={self.debug!r})")
cfg = AppConfig("localhost", 8000, True)
print(cfg)
AppConfig(host='localhost', port=8000, debug=True)
DTO(Data Transfer Object)や設定オブジェクトでは__repr__を整えるだけで、ログやインタラクティブデバッグの効率が大きく向上します。
カスタムコレクションでの__len__・__iter__実装例
class TaskList:
def __init__(self):
self._tasks = []
def add(self, task):
self._tasks.append(task)
def __len__(self):
return len(self._tasks)
def __iter__(self):
return iter(self._tasks)
def __repr__(self):
return f"TaskList({len(self)} tasks)"
tasks = TaskList()
tasks.add("backup")
tasks.add("cleanup")
print(tasks)
for t in tasks:
print("-", t)
print("count:", len(tasks))
TaskList(2 tasks)
- backup
- cleanup
count: 2
len・for・inが自然に使えることは、コレクション設計の基本です。
ロガー・トレーサーでの__enter__・__exit__活用例

import time
class ScopeTracer:
def __init__(self, name):
self.name = name
def __enter__(self):
self.start = time.time()
print(f"[ENTER] {self.name}")
return self
def __exit__(self, exc_type, exc, tb):
elapsed = time.time() - self.start
if exc:
print(f"[ERROR] {self.name}: {exc}")
print(f"[EXIT] {self.name} ({elapsed:.3f}s)")
return False # 例外はそのまま伝播
def work():
with ScopeTracer("work"):
time.sleep(0.1)
work()
[ENTER] work
[EXIT] work (0.100s)
APIクライアントでの__call__活用例

import urllib.parse
class ApiClient:
def __init__(self, base_url):
self.base_url = base_url.rstrip("/")
def __call__(self, path, **params):
url = f"{self.base_url}/{path.lstrip('/')}"
if params:
query = urllib.parse.urlencode(params)
url = f"{url}?{query}"
# 実際にはrequests.getなどを呼ぶ
print(f"GET {url}")
return {"url": url, "status": "ok"}
client = ApiClient("https://api.example.com")
res = client("users", id=1)
print(res)
GET https://api.example.com/users?id=1
{'url': 'https://api.example.com/users?id=1', 'status': 'ok'}
APIクライアントを関数のように扱えるため、DSL的な書き心地を実現できます。
まとめ
Pythonの特殊メソッドは、演算子オーバーロードからコンテナ挙動、コンテキスト管理、属性アクセス制御、メタクラスまで、言語の核となる仕組みを一通りカバーしています。
本記事で紹介した主な特殊メソッドの一覧と実用パターンを押さえておけば、自作クラスを標準ライブラリと同じような感覚で自然に扱えるようになります。
設計時に「ここはlenで長さを取りたい」「ここはwithで安全に扱いたい」と感じたら、その裏にある特殊メソッドを思い出し、必要なフックを実装していくとよいです。
