len()と.__ len __()の違いは?


回答:


102

lenコレクションの長さを取得する関数です。オブジェクトの__len__メソッドを呼び出すことで機能します。__something__属性は特別であり、通常は見た目以上のものであり、通常は直接呼び出さないでください。

それはずっと前という推論、何かの長さが機能していないメソッドコードでなければなりません取得いくつかの時点で決まったlen(a)の意味が初心者には明らかであるだろうが、a.len()明らかようではありません。Pythonが始まっ__len__た頃は存在していなかったlenし、いくつかのタイプのオブジェクトで機能する特別なものでした。これが私たちに残している状況が完全に理にかなっているかどうかに関係なく、それはとどまることです。


66

多くの場合、組み込みまたは演算子の「典型的な」動作は、__whatever__関係するオブジェクトに対して適切なマジックメソッド(のような名前を持つもの)を(異なる、より良い構文で)呼び出すことです。多くの場合、組み込みまたは演算子は「付加価値」を持っています(関係するオブジェクトに応じて異なるパスをとることができます)len-vs の場合__len__、組み込みに欠けているのは組み込みの少しの妥当性チェックだけです魔法の方法:

>>> class bah(object):
...   def __len__(self): return "an inch"
... 
>>> bah().__len__()
'an inch'
>>> len(bah())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer

あなたはへの呼び出しを参照するとlen、内蔵あなたがしている、必ずプログラムはその後続けば、むしろ例外を発生させるよりも、呼び出しは整数、非負、未満2 ** 31を返した、ということ-ときへの呼び出しが表示されxxx.__len__()、確実ではありません(コードの作成者がPythonに慣れていないか、まったく役に立たない場合を除きます;-)。

他のビルトインは、単純な健全性チェックと読みやすさを超える、さらに付加価値を提供します。ビルトインの呼び出しと演算子の使用を介して、マジックメソッドの呼び出しを介さずに機能するようにすべてのPythonを均一に設計することにより、プログラマーはどちらのケースかを覚える負担から解放されます。(エラーが発生する場合があります:2.5までは呼び出す必要がありfoo.next()ました-2.6でも下位互換性のために機能しますが、を呼び出す必要がありますnext(foo)。また3.*、魔法のメソッドには__next__"oops-ey"ではなく正しく名前が付けられていますnext!- )。

したがって、原則として、マジックメソッドを直接呼び出さないようにする必要があります(ただし、組み込みメソッドを介して間接的に常に呼び出す必要があります)。これを行う必要がある理由が正確にわかっている場合を除きます(たとえば、サブクラスでこのようなメソッドをオーバーライドする場合、サブクラスは、マジックメソッドへの明示的な呼び出しを通じて実行する必要があるスーパークラスに従う必要があります)。


私は初心者のPythonユーザーであり(初心者のプログラマーの考えではありません)、「組み込みのlenへの呼び出しが表示された場合、プログラムが例外を発生させるのではなく、その後も続行する場合は確信があります」。私はこれを試しました:def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))そしてそれはI am string2回印刷されました。もっと詳しく説明してもらえますか?
DarekNędza2014年

4
@DarekNędzaこれは、組み込みlenに関する上記とは関係ありません。len関数を定義しました。もちろん、それは何でも好きなものを返すことができます。OPは、検討中のオブジェクトに対して(関数ではなく)__len__特別なメソッドを呼び出す組み込みlenについて話しました。
Veky 2014年

@Veky lenたまたま同じ名前を持つ他の関数(例のように)ではなく、組み込み関数を呼び出していることを確認するにはどうすればよいですかlen。「組み込み関数lenを再定義しています」などの警告は表示されません。私の意見では、アレックスが彼の答えで述べたことについて確信が持てません。
DarekNędza2014年

3
アレックスは、明示的に述べている場合、あなたは組み込みを呼んでいる、そして、あなたは..._確信しています。彼はあなたがビルトインを呼び出していることを確認することについて何も言わなかった。しかし、それを知りたい場合は、次のことができますlen in vars(__builtins__).values()
Veky 2014年

1
悲しいことに、これはPythonのオブジェクトに共通の基本クラスがないことのもう1つの例です。構文コンテキストの切り替えは、常に非常に厄介です。アンダースコアメソッドを使用するのが一般的なイディオムである場合もあれば、関数のようなものを使用して多くのオブジェクトに共通の何かを行う必要がある場合もあります。多くのオブジェクトにはlenの意味上の用途がないため、これも奇妙です。時々、オブジェクトモデルはもっとC ++のような、キッチンシンキーです
。– uchuugaka

28

len()はおおよそ次と同等であると考えることができます

def len(x):
    return x.__len__()

1つの利点は、次のようなものを記述できることです。

somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist) 

の代わりに

map(list.__len__, somelist)

または

map(operator.methodcaller('__len__'), somelist)

ただし、動作が少し異なります。たとえば、intの場合

>>> (1).__len__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__len__'
>>> len(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()

2
operator.methodcaller代わりにあなたが意味すると思いますoperator.attrgetter
Elazar 2017

5

あなたはPythondドキュメントをチェックすることができます:

>>> class Meta(type):
...    def __getattribute__(*args):
...       print "Metaclass getattribute invoked"
...       return type.__getattribute__(*args)
...
>>> class C(object):
...     __metaclass__ = Meta
...     def __len__(self):
...         return 10
...     def __getattribute__(*args):
...         print "Class getattribute invoked"
...         return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__()                 # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c)          # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c)                      # Implicit lookup
10
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.