[:]

陰謀論、もとい。どこかで誰かがこーすればいいんだぜといったので、的なあれか。

リストの安全な取り回し方はどうすればいいですか的な疑問に対してどっかの大して質の高くないブロガーがそう答えてたであるとか、あるいはそもそも「コピーせねばなりません」という何かしらの強迫観念なのかもしれんし、いわゆるただただ「バカのひとつ覚え」なのかもしれんのだけれど、以下の「テンプレート」を頑なに固辞してるプログラムを今扱ってるんよな:

python だよ
1 for (idx, row) in enumerate(table_rows[:]):
2     # ...

使いもしない idx のために「必ず enumerate する」というノリももう気持ち悪いがそこは今は置いといて。table_rows[:]である。この「slice all」の意味・意図は果たして何なのか、という話。python に熟知していればこれに意味があることはわかるけれど、「意図」は計り知れない。

ワタシは「馬鹿のひとつ覚え」についてまでそこまで非難するつもりはない。初学者なんてそんなもんなのだし、最初は何かを真似するところから始めれば良いと思うし。ただこれが「進化しようとしないエンジニア」の兆候であれば、そこは批判の対象となるけれど。

そういうことではなくて、「テンプレとして [:] を必ず使う」ことの功罪については意識して欲しいと思うわけよな。「功」と「罪」は今のこの場合完全に裏表の関係にある。

「功」は table_rows がスライス可能(インデクスアクセス可能)でない場合にランタイムエラーを引き起こしてくれること、すなわち「想定外の入力を受け取った場合に正しくエラー検知出来ること」と、「コピーとして振る舞う」ことである。後者はすなわちオリジナルの table_rows を破壊せずに処理出来ることであり、これは「ループ変数を直接操作」することによって起こるある種の誤り(典型的には無限ループなど)をある程度防ぐ効果もある。前者については「罪」の方を検討すると意味がわかる。

「罪」はtable_rows がスライス可能でない場合にランタイムエラーを引き起こしてしまうこと。そう、「功」がそのまま「罪」だ。ループしたいのであるから、「スライス可能でない」としても table_rows は「イタラブル」ではあるはずであろう。これは自分で書いたコードでなくとも csv.html#reader-objects を使うことを考えてみればわかる:

1 import csv
2 with open('some.csv', newline='') as f:
3     reader = csv.reader(f)
4     next(reader)  # ヘッダ読み飛ばし
5     for row in reader:  # ヘッダは読み飛ばされている
6         print(row)

この reader はイタラブルではあるが list ではない、つまりスライス可能(インデクスアクセス可能)ではないので、「[:] を必ず使うテンプレ」を適用できない。百歩譲って「それでも頑なに[:]を使う」ならば:

1 import csv
2 with open('some.csv', newline='') as f:
3     reader = list(csv.reader(f))  # 一億行の csv でも一括で全部メモリに読み込む
4     reader = reader[1:]  # ヘッダ読み飛ばし
5     for row in reader[:]:  # ヘッダは読み飛ばされている
6         print(row)

ワタシはこのサイトでこの話題をそこそこ取り上げてる。これとかこれだね。とりわけ標準ライブラリが初心者向けとしてのわかりやすさを多少犠牲にしてでも list ではなくイタラブルを返すインターフェイスばかりを使っているのは、「性能をあなた自身で選べ」ということが最も大きな動機である。ジェネレータなのでそれだけではないけれど、そこらへんについてはリンク先に書いてあるのでそっちみとくれ。

つまり何を言いたいのかというと。「そこまで考えた上での「テンプレとして [:] を必ず使う」なのかい?」に自分自身で回答を持ってほしい、ということ。別に一方的に悪いと言ってるわけではない。実際一度実リストに全て詰めてしまってから処理する方が適切な場合も当然ある。ただしその場合は:

1 # 同じ馬鹿の一つ覚えなら以下のほうがより意図がはっきりして良いし、これならば
2 # 「スライス・インデクスアクセス可能」という要件は消える。
3 for (idx, row) in enumerate(list(table_rows)):
4     # ... table_rows が list でなくとも、row[i] というアクセスはこれなら出来る。

ということに注意。動機のうち「コピーせねば」については [:] はそのための最良のツールではない、ということである。こういうことをさ、最初のコードを書いたエンジニアがみたであろう何かしら「参考サイト」は、ちゃんと説明しとるんであろうか、と不安に思うわけよなぁ。どこぞの有名サイトだったりするのかもしらんが、だとすりゃぁさ、こういうコードが世界中(日本中?)にバラ撒かれてる可能性があるってことだもんなぁ。やんなっちゃうよほんと。