Что-то о `namedtuple` изменилось в 3.5.1?
В Python 3.5.0:
>>> from collections import namedtuple
>>> cluster = namedtuple('Cluster', ['a', 'b'])
>>> c = cluster(a=4, b=9)
>>> c
Cluster(a=4, b=9)
>>> vars(c)
OrderedDict([('a', 4), ('b', 9)])
В Python 3.5.1:
>>> from collections import namedtuple
>>> cluster = namedtuple('Cluster', ['a', 'b'])
>>> c = cluster(a=4, b=9)
>>> c
Cluster(a=4, b=9)
>>> vars(c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: vars() argument must have __dict__ attribute
Кажется, что-то о namedtuple
изменилось (или, может быть, это было что-то вроде vars()
?).
Было ли это намеренно? Не предполагается ли использовать этот шаблон для преобразования названных кортежей в словари?
Ответы
Ответ 1
Per Ошибка Python # 24931:
[__dict__
] исчез, потому что он был принципиально нарушен в Python 3, поэтому его нужно было удалить. Предоставление __dict__
разбило подклассы и произвело нечетное поведение.
Редакция, внесшая изменения
В частности, определенные подклассы без __slots__
будут вести себя странно:
>>> Cluster = namedtuple('Cluster', 'x y')
>>> class Cluster2(Cluster):
pass
>>> vars(Cluster(1,2))
OrderedDict([('x', 1), ('y', 2)])
>>> vars(Cluster2(1,2))
{}
Используйте ._asdict()
.
Ответ 2
Из docs
Именованные экземпляры кортежей не имеют словарей для каждого экземпляра, поэтому они легки и не требуют больше памяти, чем обычные кортежи.
docs (и help(namedtuple)
) говорят использовать c._asdict()
для преобразования в dict.
Ответ 3
__dict__
был реализован как @property
и был удален; вы можете увидеть изменение исходного кода:
3.5.0:
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + '({repr_fmt})' % self
@property
def __dict__(self):
'A new OrderedDict mapping field names to their values'
return OrderedDict(zip(self._fields, self))
def _asdict(self):
'Return a new OrderedDict which maps field names to their values.'
return self.__dict__
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self)
def __getstate__(self):
'Exclude the OrderedDict from pickling'
return None
3.5.1:
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + '({repr_fmt})' % self
def _asdict(self):
'Return a new OrderedDict which maps field names to their values.'
return OrderedDict(zip(self._fields, self))
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self)