初心者データサイエンティストの備忘録

調べたことは全部ここに書いて自分の辞書を作る

【Python】反復可能オブジェクトと[]で値を取得できるオブジェクト

はじめに

 Pythonを使っていると、値を複数保持している配列を扱うことが多くあります。この配列について、for文を用いることで要素の値を取り出せるものや、[]にインデックスを与えるだけで要素の値を取り出せるものがあります。この違いを勉強したので、本記事でまとめようと思います。

結論

 結論から書くと、下記の通りです。

  • for文で取得できる配列:__iter__メソッドもしくは、__getitem__メソッドを持っている。
  • []にインデックスを与えるだけで要素の値を取り出せる配列:__getitem__メソッドを持っている。

rangeオブジェクト

 rangeオブジェクトはfor文でも[]にインデックスを与えるだけでも要素の値を取得できます。下記のコードは両方とも要素の値を取り出せます。

# for文で値を取り出す
for i in range(5):
    print(i)

# []にインデックスを与えて値を取り出す
print(range(5)[0])

 これら2つの方法で値を取り出せる理由は、rangeオブジェクトが__iter__メソッドと__getitem__メソッドの両方を持っているからです。このことは、下記のコードで確認できます。

print("__iter__" in dir(range(5)))
# -> Trueと表示される

print("__getitem__" in dir(range(5)))
# -> Trueと表示される

PyTorchのDataLoader

 PyTorchのDataLoaderは、for文で要素の値を取得できますが、[]にインデックスを与える方法では要素の値を取得できません。

from torch.utils.data import DataLoader

dataloader = DataLoader(何らかのデータセット)

# for文だと要素の値を取得できる
for x in dataloader:
    print(x)


# []にインデックスを与えるだけでは、要素の値を取得できない
print(dataloader[0])
# 右記のエラーを出力する:'DataLoader' object is not subscriptable

 上記のような結果になるのは、DataLoaderオブジェクトが__iter__メソッドは持っているが、__getitem__メソッドを持っていないからです。このことは、下記のコードで確認できます。

print("__iter__" in dir(dataloader)
# -> Trueと表示される

print("__getitem__" in dir(dataloader)
# -> Falseと表示される

 なお、dataloaderに含まれる要素の値を一つだけ確認したいときは、for文を用いて__getitem__メソッドを持っているオブジェクトに変換すればOKです。例えば、下記のようにlistオブジェクトに変換します。

x_list = []

for x in dataloader:
    x_list.append(x)

# listは__getitem__メソッドを持っているので、インデックスを与えるだけで中身を確認できる
print(x_list[0])

まとめ

 本記事では、Pythonで配列の要素の値を取得する方法について説明しました。for文で取得できるか否か、[]にインデックスを与えるだけで取得できるか否かは、特殊メソッド__iter____getitem__の有無によって変わります。

  • for文で取得できる配列:__iter__メソッドもしくは、__getitem__メソッドを持っている。
  • []にインデックスを与えるだけで要素の値を取り出せる配列:__getitem__メソッドを持っている。

 また、特殊メソッドの有無は下記のコードで確認できます。

print("__init__" in dir(確認対象のオブジェクト))
print("__getitem__" in dir(確認対象のオブジェクト))

 最後に、__getitem__メソッドを持っていないオブジェクトに関しても、__getitem__メソッドを持つオブジェクト(listなど)に変換することで、[]にインデックスを与える方法で値を取得できることを示しました。