2018/06/16
[Python] __getitem__ で想定外のインデックスが来たら必ず IndexError を返すべし
Python では __getitem__()
を実装したクラスは Iterable になります。
参考
便利なのでよく使っていたのですが、for
ループで Iterable に使用した場合、__getitem__()
に想定外のインデックスが渡されることがあるので注意が必要です。
例えば、以下の例をみてください。
1 2 3 4 5 6 7 8 9 10 | class MyIterable: def __len__( self ): return 3 def __getitem__( self , i): return str (i) for i in MyIterable(): print (i) |
普通に考えると、0
, 1
, 2
と表示されて終わるように思います。
しかし、実際は無限ループに入ってしまいます。
PEP 234 をよく読むと、
Iteration の終了は IndexError
や StopIteration
等の Exception で判定されるとのこと1。
つまり、以下のように修正する必要があります。
5 6 7 8 9 | def __getitem__( self , i): if i < 0 or self .__len__() < = i: raise IndexError return str (i) |
今回、mmap を使っていたのですが、mmap
はアクセス違反をしても空のバイト列が返ってきます。
その際、そのまま空のバイト列を戻り値にしてしまうと、先のように無限ループに入ってしまうのです。
ちなみに、__getitem__()
のような特殊メソッドに関しては以下の書籍に詳しく書かれています。お勧め。
0 件のコメント:
コメントを投稿