web-dev-qa-db-ja.com

Python __ index__特別なメソッド

>>> class Thing(object):
...     def __index__(self):
...         return 1
... 
>>> thing = Thing()
>>> list_ = ['abc', 'def', 'ghi']
>>> list_[thing]
'def'
>>> dict_ = {1: 'potato'}
>>> dict_[thing]
# KeyError

thingは、リストからアクセスされたときに自分自身を1として表すことをどのように知っていますか?両方の魔法の方法は__getitem__を通過しませんか?リストに示されている使用法は、代わりに__int__を通過する可能性があるので、とにかく__index__の-​​raisond'êtreは何ですか?

14
wim

Dict andListは__getitem__を同じように実装していません。 Dictオブジェクトは、オブジェクトの__eq__の比較(__hash__)を、__getitem__で使用するキーとして使用します。

Thingをdictで使用できるようにするには、hashとeqの両方を実装する必要があります。

9

@BenoîtLatinierは彼が言ったとき正しかった:

Dict and Listは___getitem___を同じように実装していません。

ただし、もう少し情報を追加したいと思います。 ドキュメント によると:

object.__index__(self)

operator.index()を実装するために呼び出され、Pythonがスライスなどで数値オブジェクトを整数オブジェクト()に無損失で変換する必要があるときはいつでも、または組み込みのbin()hex()およびoct()関数)。このメソッドの存在は、数値オブジェクトが整数型であることを示します。整数。

太字の部分が重要です。リストのインデックス作成とスライスは、どちらも同じ方法(つまり、___getitem___)で処理されます。したがって、_Thing.__index___がスライスのために呼び出された場合、同じメソッドを使用しているため、同様にインデックス作成のために呼び出されます。この意味は:

_list_[thing]
_

ほぼ同等です:

_list_[thing.__index__()]
_

ただし、ディクショナリの場合、_Thing.__index___は呼び出されません(ディクショナリをスライスできないため、呼び出す理由はありません)。代わりに、_dict_[thing]_を実行すると、Pythonは、辞書内でthingインスタンス自体であるキーを見つけるように指示されます。これは存在しないため、KeyErrorが発生します。

おそらく、デモンストレーションが役立つでしょう:

_>>> class Thing(object):
...     def __index__(self):
...         print '__index__ called!'
...         return 1
...
>>> thing = Thing()
>>> list_ = ['abc', 'def', 'ghi']
>>> list_[thing]  # __index__ is called
__index__ called!
'def'
>>>
>>> dict_ = {1: 'potato'}
>>> dict_[thing]  # __index__ is not called
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: <__main__.Thing object at 0x01ACFC70>
>>>
>>> dict_ = {thing: 'potato'} # Works if thing is a key
>>> dict_[thing]
'potato'
>>>
_

そもそもなぜ___index___が存在するのか、その理由は PEP 0375 に徹底的に記載されています。ここではすべてを繰り返すことはしませんが、基本的には、任意のオブジェクトを整数として機能させるためです。これは、スライスやその他のいくつかのアプリケーションで必要です。

14
user2555451

さらに理解するための別の例として、ここでは _ MolsToGridSVG リスト引数を取ります。リストをある程度の長さに制限したかったのです。ここでpythonリスト、スライスインデックスを使用する必要があります。次の実装で解決しました。基本的にここでインデックスはPythonリストに使用されています。

def __index__(self):
    return 1

imagesInOneFile = int(len(smilesMolList) / noOfFiles)
svg = Draw._MolsToGridSVG(smilesMolList[:imagesInOneFile.__index__()], subImgSize=(400, 200), molsPerRow=2)

また、imagesInOneFileは整数でなければならないことを覚えておく必要があります。

0