__getitem__メソッドは、シーケンスとマッピングのプロトコルの一部としてPythonに追加されました。このマジックメソッドを使用することで、標準コレクション(list、tuple、dictなど)はインデックス、キー、スライスによるアクセスをサポートします。ユーザ定義のクラスでは、このメソッドがオブジェクトを「コレクションのように」振る舞わせることを可能にします。
__getitem__を実装しない場合、ユーザ定義のクラスはインデクシングとforループでの反復をサポートしません。単純なインデックスのみに対して実装を行うことは、スライス(slice)に対して完全な機能を望む場合には適用できず、インデックスのバリエーションを無視することはエラーに繋がります。
__getitem__を実装してインデックスとスライスタイプのオブジェクトを個別に処理することです。これにより、ユーザオブジェクトを標準的なPython構文で使用できるようになります(たとえば、your_obj[1:5]のスライスをサポートするため)。
コード例:
class MyRange: def __init__(self, n): self.n = n def __getitem__(self, item): if isinstance(item, int): # 個別のインデックス if 0 <= item < self.n: return item * 2 raise IndexError('index out of range') elif isinstance(item, slice): # スライス return [self[i] for i in range(*item.indices(self.n))] else: raise TypeError('Invalid argument type: {}'.format(type(item))) mr = MyRange(10) print(mr[3]) # 6 print(mr[2:5]) # [4, 6, 8]
重要な特徴:
__getitem__の実装だけでインデックスによる値の代入を可能にしますか?
いいえ。代入をサポートするには(your_obj[i] = value)、__setitem__を実装する必要があります。__getitem__は読み取りのみを担当します。
__getitem__は必ずスライスの場合にリストを返す必要がありますか?
いいえ。主な目的は、クラスの意味を考慮して「シーケンス」を返すことです(同じ型を返すか、たとえばtupleを返すことができます)。コンテキストに応じて意味がある限り、それは重要です。
なぜ時々 'MyClass'オブジェクトはサブスクリプト化できないというTypeErrorがありますか?
これは、my_obj[0]を実行しようとしたときに、クラスが__getitem__を実装していない場合に表示されます。クラスがサブスクリプト可能([]をサポートする)であるためには、このメソッドが必須です。
__getitem__をintのみに対して実装し、sliceを忘れました。my_obj[2:5]の試行はTypeErrorを引き起こし、コレクション処理の全体アルゴリズムが失敗します。
利点:
欠点:
__getitem__がスライスとintを個別に処理するように実装されています。スライスとインデックスが機能し、list()、map()、イテレーションのメソッドが追加の努力なしにサポートされます。
利点:
欠点: