web-dev-qa-db-ja.com

Pythonコードが長さメソッドの代わりにlen()関数を使用するのはなぜですか?

pythonには、文字列のサイズを決定するために使用されるlen()関数があることを知っていますが、なぜ文字列オブジェクトのメソッドではないのか疑問に思っていました。

更新

わかりました、私は恥ずかしいほど間違っていることに気づきました。 __len__()は、実際には文字列オブジェクトのメソッドです。文字列オブジェクトにlen関数を使用してPythonのオブジェクト指向コードを見るのは奇妙に思えます。さらに、名前としてlenだけでなく__len__を見るのも奇妙です。

191
fuentesjr

文字列には長さメソッドがあります:__len__()

Pythonのプロトコルは、長さを持つオブジェクトにこのメソッドを実装し、組み込みの len() 関数を使用します。 __iter__()および反復可能なオブジェクトで組み込みiter()関数を使用します(または、背後でメソッドを呼び出します)。

詳細については、 コンテナタイプのエミュレート を参照してください。

Pythonのプロトコルの主題に関する良い読み物は次のとおりです。 PythonおよびLeast Astonishmentの原則

170
Jonny Buchanan

この質問 に対するJimの答えが役立つかもしれません。ここにコピーします。 Guido van Rossumの引用:

まず第一に、HCIの理由から、x.len()よりもlen(x)を選択しました(def __len __()はかなり後のことです)。実際には、次の2つの理由が絡み合っています。どちらもHCIです。

(a)一部の操作では、接頭辞表記法は接尾辞よりも読みやすくなります。接頭辞(および中置記号!)演算は数学で長い伝統があります。 x *(a + b)のような式をxa + xbに書き換える簡単さと、同じことをする不器用さを比較してください生のOO表記。

(b)len(x)というコードを読んだとき、何かの長さを要求していることがわかります。これにより、2つのことがわかります。結果は整数であり、引数は何らかのコンテナです。それどころか、x.len()を読むとき、xはインターフェースを実装するか、標準のlen()を持つクラスから継承する何らかのコンテナであることをすでに知っている必要があります。マッピングを実装していないクラスにget()またはkeys()メソッドがある場合、またはファイルではないものにwrite()メソッドがある場合にときどき生じる混乱を目撃してください。

同じことを別の言い方で言うと、「len」は組み込みの操作と見なされます。私はそれを失いたくありません。 /…/

85

lenメソッドがあります:

>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>
37
unmounted

Pythonは実用的なプログラミング言語であり、len()strlistdictなどのメソッドではなく関数である理由は実用的です。

len()組み込み関数は組み込み型を直接処理します:len()のCPython実装は、実際には PyVarObject C structob_sizeフィールドの値を返します。これは、メモリ。これは、メソッドを呼び出すよりもmuch速く、属性検索を行う必要はありません。コレクション内のアイテムの数を取得することは一般的な操作であり、strlistarray.arrayなどの基本的な多様なタイプに対して効率的に動作する必要があります。

ただし、一貫性を高めるために、len(o)をユーザー定義型に適用する場合、Pythonはフォールバックとしてo.__len__()を呼び出します。 __len____abs__、および Python Data Model に記載されている他のすべての特別なメソッドにより、ビルトインのように動作するオブジェクトを簡単に作成できます。

特別なメソッドを実装することで、オブジェクトは反復をサポートし、中置演算子をオーバーロードし、withブロックなどでコンテキストを管理できます。データモデルは、作成するオブジェクトをシームレスに統合できるフレームワークとしてPython言語自体を使用します。

this one のようなGuido van Rossumからの引用に裏付けられた2番目の理由は、len(s)よりもs.len()の読み書きが簡単だからです。

len(s)という表記は、abs(n)のようなプレフィックス表記の単項演算子と一貫性があります。 len()は、abs()よりも頻繁に使用され、簡単に作成する価値があります。

歴史的な理由もあるかもしれません:Pythonに先行するABC言語(およびその設計に非常に影響力があった)には、len(s)を意味する#sと書かれた単項演算子がありました。

30
Luciano Ramalho
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.
12
Alex Coventry

ここにはいくつかの素晴らしい答えがありますので、私が自分自身を与える前に、いくつかの宝石を強調したいと思います(Rubyしゃれは意図していません)、私はここを読みました。

  • Pythonは純粋なOOP言語ではありません-それは、プログラマーが最も快適なパラダイムおよび/またはソリューションに最適なパラダイムを使用できるようにする汎用マルチパラダイム言語です。
  • Pythonには一流の関数があるため、lenは実際にはオブジェクトです。一方、Rubyにはファーストクラスの関数はありません。したがって、len関数オブジェクトには、dir(len)を実行することで検査できる独自のメソッドがあります。

独自のコードでこれが機能する方法が気に入らない場合は、好みの方法を使用してコンテナを再実装するのは簡単です(以下の例を参照)。

>>> class List(list):
...     def len(self):
...         return len(self)
...
>>> class Dict(dict):
...     def len(self):
...         return len(self)
...
>>> class Tuple(tuple):
...     def len(self):
...         return len(self)
...
>>> class Set(set):
...     def len(self):
...         return len(self)
...
>>> my_list = List([1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'])
>>> my_dict = Dict({'key': 'value', 'site': 'stackoverflow'})
>>> my_set = Set({1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'})
>>> my_Tuple = Tuple((1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'))
>>> my_containers = Tuple((my_list, my_dict, my_set, my_Tuple))
>>>
>>> for container in my_containers:
...     print container.len()
...
15
2
15
15
3
Charles Addis

また言うことができます

>> x = 'test'
>> len(x)
4

Pythonの使用2.7.3。

1
SpanosAngelos