Pythonは歴史が長いので、色々な方がその理由を解説されていますが、私も自分の言葉で説明したくなったので一本書きます。
その理由は、生みの親(かつての慈悲深き終身独裁者)Guido氏の意向です。
Guido氏の考えを覗きに行きましょう。
目次
デザインと歴史 FAQ
公式ドキュメントの中にはFAQのページがあります。
その中に表題の疑問にズバリな項があります!
Python にメソッドを使う機能 (list.index() 等) と関数を使う機能 (len(list) 等) があるのはなぜですか?
なんでlist.index()はある1のに、list.len()がないんですか!!
この項目は翻訳があるので日本語で読めます。
それを読んでもいいのですが、リンクされているGuido氏のメールを覗いてみましょう(一次情報ですからね)
Guido氏のメール
このメールはlist.len()メソッドに反対するものです。
2つのPython rationaleを持って説明しています
1つ目:Human Computer Interaction(HCI)から
2つの理由が説明されます。
この2つは結びついている(intertwined)とのことでした
(a) For some operations, prefix notation just reads better than postfix
(a)についてはFAQにそのまま掲載されていそうです
(a) 幾つかの演算では、接頭辞は接尾辞よりも単純に読みやすいからです。
ふむふむ、len(list)(接頭辞の書き方)の方が、list.len()(接尾時の書き方)よりも読みやすい
(b) When I read code that says len(x) I *know* that it is asking for the length of something.
(b)もFAQに掲載されていそうでした。
(b)の理由は人間にとっての分かりやすさと理解しました。
自分の理解のために構造化しました(メールにない情報はIMOで補っています)
len(x)
というコードは、なにか(x)の長さを尋ねているコード- 結果は整数
- 引数のxはある種のcontainer
- IMO:このxはcontainerということ以外は分からなくてよい
x.len()
というコード
(b)に続く段落は、言い換えです(ここから下はFAQにはありません)
Saying the same thing in another way, I see 'len' as a built-in *operation*.
Guido氏は'len'を組み込みの操作として見ているとのこと。
ここはかなり強い想いがあるようで、メソッドにしたいという意見にも配慮しつつ、
'def len(self): ...' certainly sounds like you want to demote it to an ordinary method.
'def len(self): ...'とメソッドにする案は、lenという操作を通常のメソッドに格下げしたいように聞こえる。
Guido氏としては、長さを尋ねる操作をメソッドよりも上位のレベルで捉えていることが分かりました。
これは私の感想ですが、メソッドよりも上位の操作は、+
などの演算子やfor hoge in foo:
のような制御構造と同じように見るということかなと思いました
2つ目:特殊メソッドの命名規約から
もう1つの理由にいきましょう。
特殊メソッドとは、用語集によると
ある型に特定の操作、例えば加算をするために Python から暗黙に呼び出されるメソッド。
メソッド名の最初と最後にアンダースコア 2 つがついています。
このアンダースコアを2つ付ける(Python界隈では「ダンダー」と呼ばれる)命名規則に関係した理由でした。
- なぜ特殊メソッドの名前を単に
special
ではなく__special__
としたのか - Guido氏は特殊メソッドが対応する操作を、クラスでoverrideすることを見越している
__special__
という特殊メソッド名であれば、通常のメソッド名とは異なるのでユーザが誤って意図せずにoverrideすることがないspecial
という特殊メソッド名だと、すべての特殊メソッド名を頭に入れない限り、不幸なことに、誤って意図せずにoverrideしてしまう
思うに、__special__
という特殊メソッド名によって、「正しい使い方を簡単に」を実現したのではないでしょうか?
- Pythonを始めた人
- 「長さはlen()関数」とだけ覚えればよい
- クラスにlen()メソッドを定義しても、何も影響はない
- Pythonに習熟した人
- 特殊メソッド
__len__()
の存在に気づき、定義したクラスの振る舞いをカスタマイズできる
- 特殊メソッド
参考文献(先人に感謝)
「サイズを取るメソッドは.length()」という 暗黙のルールができてしまい、そのルールが頭に入っていない人が一貫性の無いコードを書いてしまう。
Pythonは、何かのルールに準拠するためのメソッド(以降、特殊メソッド)は「__???__」という形にする、という一般ルールをつくり、それを interface の代わりにした。
__len__ に対するインタフェースは len() という組み込み関数になっている。
『Python Distilled』 7.6より
(※Pythonicという言葉は)通常はオブジェクトがPythonの他の部分とうまく調和していることを指します。
これは (略) Pythonの核となる機能を合理的な範囲でサポートすることを意味します。
大半の場合、(略) あらかじめ定義された特殊メソッドをクラスに実装することでPythonicとなります。
Guido氏の意向の理解まとめ
nikkieの言葉で再構成したまとめです。
- 長さを尋ねる操作は、メソッドよりも上位のレベルで捉えている
+
演算子やfor
文などと同列
- これらの上位レベルの操作はPython言語は特殊メソッドで提供
- 特殊メソッドをPython処理系が暗黙に呼び出す仕組み
- 特殊メソッドの命名規則は
__special__
(アンダースコア2つで挟む)
気づいたのですが、この意向によりPythonという言語は、習熟度に応じた棲み分けが実現できているんですね!
- 入門時
- 長さはlen()関数、加算は
+
、反復はfor文、... - 特殊メソッドを一切知る必要がない
- 長さはlen()関数、加算は
- 慣れてきたら
- ようこそ、特殊メソッド(表現力豊かなコードが書ける!)
P.S. Pythonに飼い慣らされたnikkieは
他の言語を使うときに「Pythonでいうlen()関数はないの?」となっていつも洗礼を浴びます。
例えばKotlinですが、
- 文字列の長さは
.length
- コレクションの中のListは
.size
🤯
「郷に入っては郷に従え」だなと思っています。
- https://docs.python.org/ja/3/library/stdtypes.html#common-sequence-operations を参照ください↩
- 知ったきっかけはPyCon JPの過去の発表です。Pythonはどうやってlen関数で長さを手にいれているの? | PPT(slide=52)↩