Подтвердить что ты не робот

Что-то о `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()?).

Было ли это намеренно? Не предполагается ли использовать этот шаблон для преобразования названных кортежей в словари?

4b9b3361

Ответ 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

Именованные экземпляры кортежей не имеют словарей для каждого экземпляра, поэтому они легки и не требуют больше памяти, чем обычные кортежи.

docshelp(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)