2016年9月9日

collections.namedtuple の注意点

collections.namedtuple のちょっとした注意点を紹介します。

namedtuple は tuple を継承したものです。

>>> from collections import namedtuple
>>> Point = namedtuple('Point', 'x y z')

# namedtuple は tuple のサブクラス
>>> issubclass(Point, tuple)
True

当然、tuple のアトリビュートは namedtuple にも引き継がれます。
# tuple のアトリビュート
>>> dir(tuple)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '_
_eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs
__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__'
, '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__
rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'i
ndex']

# namedtuple のアトリビュート
>>> dir(Point)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '_
_eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs
__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__'
, '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '
__repr__', '__rmul__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__s
ubclasshook__', '_asdict', '_fields', '_make', '_replace', '_source', 'count', '
index', 'x', 'y', 'z']

ここで注目すべきは、tuple は count と index という _(アンダーバー)で始まらないアトリビュートを2つ持っている点です。即ち、namedtuple の要素名として count か index を指定した場合、その namedtuple は親クラスである tuple のインターフェースを変えてしまった良くないサブクラス、ということになります。
結論として、namedtuple の要素名として count と index は使うべきではありません。
>>> WrongNames = namedtuple('WrongNames', 'count index')
>>> wrong_names = WrongNames(1, 2)

# count は要素名になってしまった
>>> wrong_names.count
1
# tuple の count() を期待するとエラー
>>> wrong_names.count(1)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'int' object is not callable

# index は要素名になってしまった
>>> wrong_names.index
2
# tuple の index() を期待するとエラー
>>> wrong_names.index(1)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'int' object is not callable

0 件のコメント:

コメントを投稿