[Python] __getitem__の引数・動作について

 クラスに__getitem__を実装すると添え字やスライスで要素にアクセスできるようになります。

 今回はその__getitem__関数の挙動や引数についてです。

__getitem__の挙動


 クラスに__getitem__を実装することでリストのようにインデックスなどで要素にアクセスできるようになります。

 value[<インデックスなど>]を実行するとvalueのクラスの__getitem__が<インデックスなど>を引数に呼ばれます。

 添え字やスライスなどのときに__getitem__の引数はどういう値になるのか見てみましょう。

 __getitem__の挙動を確かめるために以下のサンプルを動かしてみます。出力結果はコメントにある通りです。

 文字列でもリストでも__getitem__のitem引数に渡せるので、dict型みたいに文字列でアクセスとかnumpyみたいにnumpy配列使ってアクセスなど実装次第でできます。

 注意なのがスライスの場合。item引数がsliceというクラスになります。

from typing import Tuple, List


class StrIntList:
    def __init__(self):
        self._ls: List[Tuple[str, int]] = []

    def __getitem__(self, item):
        print(item, type(item))


a = StrIntList()
a[1]  # 1 <class 'int'>
a["test"]  # test <class 'str'>
a[[1,2,3]]  # [1, 2, 3] <class 'list'>
a[1:10:-1]  # slice(1, 10, -1) <class 'slice'>

Sliceクラスについて


 sliceは以下のようにアクセスできます。

 startは配列の開始インデックス、stopは終了インデックス、stepはスライスの3つ目の引数である次要素はいくつ先のデータにするかの値です。

...
    def __getitem__(self, item):
        print(item, type(item))
        if isinstance(item, slice):
            print(item.start, item.stop, item.step)  # ここ
...

 ここで注意なのがls[:100]みたいな、値を省略する場合。省略した部分は以下のサンプルのようにNoneが入ります。

 __getitem__を実装するときはsliceはstart,stop,stepそれぞれNoneを考慮する必要があります。

from typing import Tuple, List


class StrIntList:
    def __init__(self):
        self._ls: List[Tuple[str, int]] = []

    def __getitem__(self, item):
        if isinstance(item, slice):
            print(item.start, item.stop, item.step)


a = StrIntList()
a[1:10:-1]  # 1 10 -1
a[:10]  # None 10 None
a[1:]  # 1 None None

コメントを残す

メールアドレスが公開されることはありません。