回答:
私の知る限り、len
この点で特別であり、歴史的なルーツがあります。
ここにFAQからの引用があります:
Pythonが一部の機能(list.index()など)にメソッドを使用し、他の機能(len(list)など)に関数を使用するのはなぜですか?
主な理由は歴史です。関数は、タイプのグループに対して一般的であり、メソッドをまったく持たないオブジェクト(タプルなど)でも機能することを目的とした操作に使用されました。また、Pythonの機能機能(map()、apply()など)を使用するときに、アモルファスオブジェクトのコレクションに簡単に適用できる関数があると便利です。
実際、組み込み関数としてlen()、max()、min()を実装する方が、実際には、各タイプのメソッドとして実装するよりもコードが少なくて済みます。個々のケースについて疑問を投げかけることはできますが、これはPythonの一部であり、そのような根本的な変更を今行うには遅すぎます。関数は、大規模なコード破損を回避するために残しておく必要があります。
他の「魔法の方法」(実際にはPythonの民間伝承では特別な方法と呼ばれています)は多くの意味があり、他の言語にも同様の機能があります。これらは主に、特別な構文が使用されたときに暗黙的に呼び出されるコードに使用されます。
例えば:
等々...
Zen of Pythonから:
あいまいな状況に直面して、推測する誘惑を拒否してください。
それを行うには、明白な方法が1つ(できれば1つだけ)あるはずです。
カスタムメソッドで、開発者のような、別のメソッド名を自由に選択するだろう-これが理由の一つであるgetLength()
、length()
、getlength()
または全く。Pythonでは、共通の関数len()
を使用できるように厳密な名前が付けられています。
多くのタイプのオブジェクトに共通するすべての操作は__nonzero__
、__len__
やのような魔法のメソッドに入れられ__repr__
ます。ただし、それらはほとんどオプションです。
演算子のオーバーロードはマジックメソッド(など__le__
)でも行われるため、他の一般的な操作にも使用するのは理にかなっています。
Pythonは「マジックメソッド」という単語を使用します。これらのメソッドは、プログラムに対して実際にマジックを実行するためです。Pythonのマジックメソッドを使用する最大の利点の1つは、オブジェクトを組み込み型のように動作させる簡単な方法を提供することです。つまり、基本的な演算子を実行する醜い、直感に反する、非標準的な方法を回避できるということです。
次の例について考えてみます。
dict1 = {1 : "ABC"}
dict2 = {2 : "EFG"}
dict1 + dict2
Traceback (most recent call last):
File "python", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
辞書タイプは追加をサポートしていないため、これはエラーになります。次に、辞書クラスを拡張して、「__ add__」マジックメソッドを追加します。
class AddableDict(dict):
def __add__(self, otherObj):
self.update(otherObj)
return AddableDict(self)
dict1 = AddableDict({1 : "ABC"})
dict2 = AddableDict({2 : "EFG"})
print (dict1 + dict2)
これで、次の出力が得られます。
{1: 'ABC', 2: 'EFG'}
したがって、このメソッドを追加することで、突然マジックが発生し、以前に発生していたエラーはなくなりました。
私はそれがあなたに物事を明確にすることを願っています。詳細については、以下を参照してください。
Pythonのマジックメソッドのガイド(Rafe Kettler、2012年)
これらの関数の一部は、(スーパークラスの抽象メソッドなしで)実装できる単一のメソッドを超えるものを実行します。たとえばbool()
、次のように動作します。
def bool(obj):
if hasattr(obj, '__nonzero__'):
return bool(obj.__nonzero__())
elif hasattr(obj, '__len__'):
if obj.__len__():
return True
else:
return False
return True
また、bool()
常にTrueまたはFalseを返すことを100%確信できます。メソッドに依存している場合、何が返されるかを完全に確信することはできません。
比較的複雑な実装を持つ他のいくつかの関数(基礎となるマジックメソッドよりも複雑である可能性が高い)はiter()
、およびcmp()
、およびすべての属性メソッド(getattr
、setattr
およびdelattr
)です。のようなものは、int
強制を行うときにマジックメソッドにアクセスします(実装できます__int__
)が、型として二重の役割を果たします。 len(obj)
実際には、とはまったく異なるとは思えない1つのケースobj.__len__()
です。
hasattr()
私が使用するtry:
/ except AttributeError:
し、代わりのをif obj.__len__(): return True else: return False
私は言うだろうreturn obj.__len__() > 0
が、それらは単なる文体ものです。
bool(x)
と呼ばれx.__nonzero__()
ます)では、このメソッドは機能しません。boolインスタンスにはmethod __nonzero__()
があり、objがboolになると、コードはそれ自体を呼び出し続けます。おそらくbool(obj.__bool__())
、あなたが扱ったのと同じように扱われるべき__len__
ですか?(または、このコードは実際にPython 3で機能しますか?)
len(x)
とx.__len__()
、前者を超え長さについてOverflowErrorを上げることであるsys.maxsize
後者は、一般的にPythonで実装タイプのためではないだろうが、。ただし、これは機能よりもバグです(たとえば、Python 3.2のrangeオブジェクトは、主に任意の大きな範囲を処理できますがlen
、それらを使用すると失敗する可能性があります__len__
その理由は主に歴史的なものですが、Python len
には、メソッドではなく関数を使用するのに適したいくつかの特徴があります。
Pythonでいくつかの動作は、例えば、メソッドとして実装されているlist.index
とdict.append
、他のものは、例えば、呼び出し可能オブジェクトとマジックメソッドとして実装されている間str
とiter
し、reversed
。2つのグループは十分に異なるので、異なるアプローチが正当化されます。
str
、int
および友達はタイプです。コンストラクタを呼び出す方が理にかなっています。iter
が利用できない__getitem__
場合に呼び出さ__iter__
れ、メソッド呼び出しに適合しない追加の引数をサポートします。同じ理由で、最近のバージョンのPythonではにit.next()
変更さnext(it)
れています。__iter__
と__next__
それが呼ばれています- for
ループ。一貫性を保つために、関数の方が優れています。そして、それは特定の最適化にとってそれをより良くします。repr
のように動作しstr
ません。持つstr(x)
対は、x.repr()
混乱を招くことになります。isinstance
。getattr(x, 'a')
ことのもう一つの方法であるx.a
とgetattr
、前述の資質の多くを共有します。私は個人的に、最初のグループをメソッドのように、2番目のグループをオペレーターのように呼んでいます。それはあまり良い区別ではありませんが、何らかの形で役立つことを願っています。
これを言っても、len
2番目のグループには完全には適合しません。それは最初のものの操作により近いですが、唯一の違いはほとんどすべての操作よりも一般的であることです。しかし、それが行う唯一のことはを呼び出すこと__len__
であり、それはに非常に近いL.index
です。ただし、いくつかの違いがあります。たとえば__len__
、などの他の機能の実装のためbool
に呼び出されるlen
場合があります。メソッドが呼び出された場合、まったく異なる動作bool(x)
をするカスタムlen
メソッドで中断する可能性があります。
つまり、クラスが実装する可能性のある非常に一般的な機能のセットがあり、これらは、演算子、特別な関数(通常は演算子のように実装よりも多くの機能を果たす)、オブジェクトの構築中、およびそれらすべてにアクセスできます。いくつかの共通の特徴を共有します。残りはすべてメソッドです。そしてlen
、そのルールのいくぶん例外です。
上記の2つの投稿に追加することは多くありませんが、すべての「マジック」関数は実際にはまったくマジックではありません。これらは、インタプリタの起動時に暗黙的/自動的にインポートされる__ builtins__モジュールの一部です。すなわち:
from __builtins__ import *
プログラムが開始する前に毎回発生します。
Pythonがインタラクティブシェルに対してのみこれを実行し、必要なビルトインからさまざまなパーツをインポートするためのスクリプトが必要な場合は、常にもっと正しいと思っていました。また、おそらく異なる__ main__処理は、シェルと対話型では良いでしょう。とにかく、すべての機能をチェックして、それらがない場合の状態を確認してください。
dir (__builtins__)
...
del __builtins__
len()
かreversed()
、さまざまなタイプのオブジェクトに適用されるが、そのような方法としてappend()
のみなど、シーケンスに適用される