Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Python辞典

  1. トップページ
  2. Python辞典
  3. __len__() / __getitem__() / __iter__()

__len__() / __getitem__() / __iter__()

ダンダーメソッド(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()関数に対応する。
サンプルコード
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('りんご', 150)
cart.add('みかん', 100)
cart.add('バナナ', 200)

print(len(cart))            # 3
print(cart[0])              # {'name': 'りんご', 'price': 150}
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)]
概要

ダンダーメソッドを実装することで、自作クラスにPythonの標準的な操作を追加できます。これを「演算子オーバーロード」とも呼びます。例えば__add__を実装すれば+演算子が使えるようになり、__iter__と__next__を実装すればforループで使えるイテレータになります。

比較演算子を実装する場合、__eq__だけでなく__lt__・__le__・__gt__・__ge__もすべて実装するのは手間がかかります。その場合は『functools.total_ordering』デコレータを使うと、__eq__と__lt__の2つだけ実装すれば残りの比較演算子を自動生成できます。

ダンダーメソッドを直接呼び出すことは非推奨で(obj.__len__()ではなくlen(obj)を使う)、これはPythonの設計哲学に基づいています。直接呼び出しと比べ、組み込み関数経由では型チェックなどの追加処理が行われる場合があります。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。