先日、PEP 618 (Add Optional Length-Checking To zip) が Accept されたというコミットを見かけました。
そこで、今回は PEP 618 を読んでみようと思います。
概要
-
zip()
関数を使うとき、暗黙的に各要素の長さが同じであることを期待していることがある (ことが多い) -
長さの異なる要素を誤って与えてしまうと、意図せずデータを欠損してしまうことになる
>>> list(zip([1,2,3], [4])) # 2, 3 は失われてしまう [(1, 4)]
-
次のような関数があるときに、リストを渡すと意図通りに動くが、イテレータを渡すとうまく動かない (イテレータが先に進んでしまうので)。
def apply_calculations(items): transformed = transform(items) for i, t in zip(items, transformed): yield calculate(i, t)
-
zip()
にオプションを追加し、各要素が同じ長さであることをチェックする
アプローチ
Python 3.10 に zip()
関数に strict
というパラメータが追加されました。
strict
に正の値を指定した場合、各要素の長さが等しくないときに ValueError
が発生します。
>>> for item in zip([1, 2, 3], [4], strict=True):
... print(item)
...
(1, 4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: zip() argument 2 is shorter than argument 1
zip()
の第2引数が第1引数より短い、というエラーが出ています。
ちなみに、長さが一致しないというのを検知するまでループが回っている点には注意が必要です。
なお、デフォルトではいままでの挙動のままのままです(strict=False
相当、つまり長さが異なる場合はデータを捨てる)。
>>> for item in zip([1, 2, 3], [4]):
... print(item)
...
(1, 4)
>>>
感想
- 言われてみるとうっかりミスでデータ欠損を起こしそうな予感があるので、これは嬉しい
- でも、明示的に
strict=True
と指定しないといけないので、指定しわすれてトラブルになりそう - イテレータの例はやらかしそうな気がした (すぐに気づくとは思うけど…)
- 3.10 が楽しみですね