__len__() / __getitem__() / __iter__()
| 対応: | Python 2(2000) |
|---|
ダンダーメソッド(dunder method)とは、アンダースコアを2つ重ねた名前の特殊メソッドです(double underscoreの略)。組み込み関数や演算子と連動して動作し、自作クラスにPythonの標準的な振る舞いを持たせることができます。ダンダーメソッドを直接呼び出すことは稀で、通常はlen()関数や[]演算子などを使うと内部でダンダーメソッドが呼ばれます。
主要なダンダーメソッド
| メソッド | 概要 |
|---|---|
| __len__(self) | len()関数呼び出し時に使われる。要素数を整数で返す。 |
| __getitem__(self, key) | obj[key]でアクセスしたときに呼ばれる。 |
| __setitem__(self, key, val) | obj[key] = valで代入したときに呼ばれる。 |
| __delitem__(self, key) | del obj[key]で削除したときに呼ばれる。 |
| __iter__(self) | iter()関数やforループでイテレータを取得するときに呼ばれる。 |
| __next__(self) | next()関数でイテレータから次の要素を取得するときに呼ばれる。 |
| __contains__(self, item) | item in objで使われる。 |
| __eq__(self, other) | ==演算子で比較するときに呼ばれる。 |
| __lt__(self, other) | <演算子で比較するときに呼ばれる。 |
| __add__(self, other) | +演算子で加算するときに呼ばれる。 |
| __len__(self) | len()関数に対応する。 |
サンプルコード
sample_dunder_methods.py
class ShoppingCart:
"""ショッピングカートのサンプルクラス"""
def __init__(self):
self._items = []
def add(self, item, price):
self._items.append({'name': item, 'price': price})
def __len__(self):
"""len(cart) で商品数を返す"""
return len(self._items)
def __getitem__(self, index):
"""cart[0] で商品を取得する"""
return self._items[index]
def __setitem__(self, index, value):
"""cart[0] = value で商品を上書きする"""
self._items[index] = value
def __delitem__(self, index):
"""del cart[0] で商品を削除する"""
del self._items[index]
def __contains__(self, name):
"""'碇シンジ' in cart でパイロット名を検索する"""
return any(item['name'] == name for item in self._items)
def __iter__(self):
"""for item in cart でループできるようにする"""
return iter(self._items)
def __eq__(self, other):
"""== 演算子で比較する"""
if not isinstance(other, ShoppingCart):
return NotImplemented
return self._items == other._items
cart = ShoppingCart()
cart.add('碇シンジ', 75)
cart.add('綾波レイ', 90)
cart.add('惣流アスカ', 85)
print(len(cart)) # 3
print(cart[0]) # {'name': '碇シンジ', 'price': 75}
print('綾波レイ' in cart) # True
print('渚カヲル' in cart) # False
for item in cart:
print(f"{item['name']}: {item['price']}点")
del cart[1] # 綾波レイを削除
print(len(cart)) # 2
# 比較演算子のカスタマイズ(__lt__ を使ったソート)
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __lt__(self, other):
return self.score < other.score
def __eq__(self, other):
return self.score == other.score
def __repr__(self):
return f"Student({self.name}, {self.score})"
students = [Student('碇シンジ', 75), Student('綾波レイ', 90), Student('惣流アスカ', 60)]
students.sort() # __lt__ があれば sorted() も使える
print(students) # [Student(惣流アスカ, 60), Student(碇シンジ, 75), Student(綾波レイ, 90)]
python3 dunder_methods.py
3
{'name': '碇シンジ', 'price': 75}
True
False
碇シンジ: 75点
綾波レイ: 90点
惣流アスカ: 85点
2
[Student(惣流アスカ, 60), Student(碇シンジ, 75), Student(綾波レイ, 90)]
概要
ダンダーメソッドを実装することで、自作クラスにPythonの標準的な操作を追加できます。これを「演算子オーバーロード」とも呼びます。演算子オーバーロードとは、『+』や『==』などの演算子が自作クラスでどう動作するかを定義する仕組みです。例えば『__add__』を実装すれば+演算子が使えるようになり、『__iter__』と『__next__』を実装すればforループで使えるイテレータになります。
比較演算子を実装する場合、『__eq__』だけでなく『__lt__』・『__le__』・『__gt__』・『__ge__』もすべて実装するのは手間がかかります。その場合は『functools.total_ordering』デコレータを使うと、『__eq__』と『__lt__』の2つだけ実装すれば残りの比較演算子を自動生成できます。
ダンダーメソッドを直接呼び出すことは非推奨で(『obj.__len__()』ではなく『len(obj)』を使う)、これはPythonの設計哲学に基づいています。直接呼び出しと比べ、組み込み関数経由では型チェックなどの追加処理が行われる場合があります。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。