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

methaneのブログ

このブログに乗せているサンプルコードはすべてNYSLです。

len が関数になっている理由

Python

http://d.hatena.ne.jp/pashango_p/20090702/1246550203

len()がリストのメソッドでないのも同じ理由です。
オブジェクト指向的に考えれば、リストのメソッドであるべきなのに、わざわざビルトイン関数にしたんです。

オブジェクト指向的に考えれば、リストのメソッドであるべき」って感じで、オブジェクト信者はそれが正義みたいに考えちゃうんだろうね・・・
Pythonは合理主義。「オブジェクト指向的に○○」よりも、一貫した少なくて明確なルールを重視する。

len() が .length() メソッドだったらどうなるか。あるコンテナは .length() の代わりに、 .len() や .size() という名前を使ってしまうかもしれない。「サイズを取るメソッドは.length()」という 暗黙のルールができてしまい、そのルールが頭に入っていない人が一貫性の無いコードを書いてしまう。

この問題を解決するには、Javaで言うinterfaceを用意してコンテナ型は必ずこれを実装しないといけない、とする手もあるが、duck typingの動的片付とは共存しにくい。

そこで、Pythonは、何かのルールに準拠するためのメソッド(以降、特殊メソッド)は「__???__」という形にする、という一般ルールをつくり、それを interface の代わりにした。これなら、暗黙のルールに精通していない人も「__???__」というメソッド名を避ければ気づかないうちにルールを破ってしまうことが無くなる。予約語以外の「暗黙のルールで使わないほうが良い語」を気にしなくてよくなる。

さて、特殊メソッドは、直接呼ぶことも出来るが基本的には何かのインタフェースを通して呼ぶ事になる。__eq__ というメソッドは == という演算子によって呼ばれるし、__str__ はstr型のコンストラクタや"%s"に対するフォーマット等文字列への変換で呼ばれる。そして __len__ に対するインタフェースは len() という組み込み関数になっている。他にも __iter__ も iter() という組み込み関数がインタフェースになっている*1

残念ながら、歴史的経緯によりこの一貫性に則っていない部分もある。たとえばイテレータが実装するメソッドは .next() だ。これは Python 3.0 では修正され、 __next__() になる。一貫性を保つために、10年に一回くらいこういった下位互換性を維持できない大掃除が必要になる。

*1:for x in y: でも y.__iter__ が呼ばれるのでiter()だけが__iter__()のインタフェースというわけではないが