Наследование от базового класса namedtuple-Python

этот вопрос задает противоположность наследовать namedtuple от базового класса в python, где целью является наследование подкласса от namedtuple, а не наоборот.

в обычном наследовании это работает:

class Y(object):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c


class Z(Y):
    def __init__(self, a, b, c, d):
        super(self.__class__, self).__init__(a, b, c)
        self.d = d

[выход]:

>>> Z(1,2,3,4)
<__main__.Z object at 0x10fcad950>

но если базовый класс является namedtuple:

from collections import namedtuple

X = namedtuple('X', 'a b c')

class Z(X):
    def __init__(self, a, b, c, d):
        super(self.__class__, self).__init__(a, b, c)
        self.d = d

[выход]:

>>> Z(1,2,3,4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __new__() takes exactly 4 arguments (5 given)

вопрос можно ли наследовать namedtuples как базовый класс в Python? Есть и как?

2 ответов


вы можете, но вы должны переопределить __new__, который вызывается неявно перед __init__:

class Z(X):
  def __new__(cls, a, b, c, d):
    self = super(Z, cls).__new__(cls, a, b, c)
    self.d = d
    return self

>>> z = Z(1, 2, 3, 4)
>>> z
Z(a=1, b=2, c=3)
>>> z.d
4

но d будет просто независимым атрибутом!

>>> list(z)
[1, 2, 3]

Я думаю, вы можете достичь того, что хотите, включив все поля в исходном именованном кортеже, затем корректируя количество аргументов используя __new__ как schwobaseggl предлагает выше. Например, обратиться случай max, где некоторые из входных значений должны быть вычислены вместо того, чтобы поставить непосредственно, следующие работы:

from collections import namedtuple

class A(namedtuple('A', 'a b c computed_value')):
    def __new__(cls, a, b, c):
        computed_value = (a + b + c)
        return super(A, cls).__new__(cls, a, b, c, computed_value)

>>> A(1,2,3)
A(a=1, b=2, c=3, computed_value=6)