python での duck typing は難しい

python に限らず、動的型付言語では一緒かと思いますが、pythonで出会ったのでそのようなタイトルになっています。

何が起こったのか

某所にて、 pandas 0.25.3 から pandas 1.0 にバージョンアップしたら壊れたという話があり、壊れている箇所について、疑似的に再現したコードを見せられ、それとなく話をしたり、手元で再現してみた結果、問題の個所と おそらくの原因が分かったので issue をたてました。

とりあえずの解決

issue に対して、pull request を送り、無事、issueは閉じられました。

ここでの修正は、 バイナリストリームかどうかを BufferedIOBase であるかどうか、という判定をしており、 python のIOで定義されているもう一つの バイナリストリームの基底クラス RawIOBase かどうかも判定に加えるというものです。

それでもダメだった

上記の修正によって一見、きちんと動くように見えますが、実際、某所にてそれでは動かなかったという話が出ました。

原因は、 duck typing ぽい判定の仕方にあります。 python では file like object という概念(?)があります。 これは何かというと、 read() とか write() とかのような、ファイルで規定されているようなメソッドがあるもの全般を指します。

それは、メソッドがあれば、別に IO で定義されている基底クラスの派生クラスである必要は全くないということです。

そのことについて、新たにissue がたてられています。

何がしんどいのか

duck typing において、型の話が全くないからです。なんなら、引数についても全く規定なく使われています。ioでの記載

つまり、この場合、読み込みで要求される file like object というのは read() があればよく、その戻り値が 文字列やバイナリ配列ではなく、たとえintの配列であってもかまわない。みたいな感じです。

しかも、実行時にこれらのエラーが発覚するのは、 file like object を引数として取るところではなく、 file like object の read() を利用したタイミングなので、エラーが出る箇所が結構ズレた場所になる可能性も高いということです。

結論

やっぱり型が欲しいよね。という話でした。