Python: расширение предопределенного названного кортежа

У меня есть следующий именованный кортеж:

from collections import namedtuple
ReadElement = namedtuple('ReadElement', 'address value')

а затем я хочу следующее:

LookupElement = namedtuple('LookupElement', 'address value lookups')

Существует дублирование между двумя именами, как я могу подклассифицировать ReadElement для добавления дополнительного поля?

class LookupElement(ReadElement):
    def __new__(self, address, value, lookups):
        self = super(LookupElement, self).__new__(address, value)
        l = list(self)
        l.append(lookups)
        return tuple(l)

Однако кортеж создается там тогда в операторе new, если я изменяю себя как список, я потеряю информацию о типе, как я могу избежать этого?

Ответ 1

Вы можете подклассифицировать класс namedtuple -produced, но вам нужно более внимательно изучить сгенерированный класс. Вам нужно добавить еще один атрибут __slots__ с дополнительными полями, обновить атрибут _fields, создать новые методы __repr__ и _replace (они жестко задают список полей и имя класса) и добавлять дополнительные объекты property для дополнительных полей. См. Пример в документации.

Это все слишком много работает. Вместо подкласса я просто повторно использовал атрибут somenamedtuple._fields типа источника:

LookupElement = namedtuple('LookupElement', ReadElement._fields + ('lookups',))

Аргумент field_names конструктору namedtuple() не обязательно должен быть строкой, он также может быть последовательностью строк. Просто возьмите _fields и добавьте больше элементов, объединив новый кортеж.

Демо:

>>> from collections import namedtuple
>>> ReadElement = namedtuple('ReadElement', 'address value')
>>> LookupElement = namedtuple('LookupElement', ReadElement._fields + ('lookups',))
>>> LookupElement._fields
('address', 'value', 'lookups')
>>> LookupElement('addr', 'val', 'lookup') 
LookupElement(address='addr', value='val', lookups='lookup')

Это означает, что расширенный тип не является подклассом базового типа. Если у вас должна быть иерархия классов, вместо того, чтобы пытаться сделать именованные кортежи подходящими для этой модели, я бы вместо этого переключился на dataclasses. Dataclasses могут служить одной и той же целью в большинстве случаев, когда используются имена кортежей, но их легко подклассы.