読者です 読者をやめる 読者になる 読者になる

ジェネレーターとCPython(下)

Python

 前回のエントリで、組み込み関数にジェネレーターを与えた時、内部でどのように扱われるか、ということについて、だらだらと書きましたが、結局のところ、これは現在のCPython実装での振る舞いにすぎません。
 別のPython実装では、また違った扱われ方がなされ、ジェネレーターと具象シーケンス・オブジェクトの時間・メモリ効率の差も当然異なってきます。


 ただし、allとかanyといった関数は、論理的に考えれば、どんな言語での実装であっても大差がないことは予想できますし、ジェネレーターを使うべきか、具象シーケンス・オブジェクトを使うべきかに関する指針は、はっきりしていると思います。
 一方、mapのように、ある処理にすべての要素が必要な場合、CPythonにおいても、「シーケンス/ジェネレーターから一要素を取得、その要素に処理を適用、次の要素を取得...」というように要素毎に処理を行っていく実装も可能ではありますが、CPythonでは時間効率を最大化する方針で実装が行われているために、mapや類似の関数では、リスト/タプルに変換してから、要素配列に逐次アクセスするというやり方で実装されることが多いようです。


 典型的なのは、str.join(sequence)の実装で、メモリ割り当ての回数を最小化し、かつ、余計な文字列オブジェクトを作らないために、「Cで文字列の連結を行うならばこれしかない」というようなコードで書かれています。
 これがIronPythonならば、同じstr.join(sequence)でも、より.NETらしいスタイル、つまり、EnumeratorとStringBuilderで文字連結を行うようになっていて、与えたシーケンス/ジェネレーターが、リスト/タプルに強制的に変換されることはありません。