2017-02-22 108 views
8

Этот вопрос задает противоположное значение Inherit namedtuple from a base class in python, где целью является наследование подкласса из namedtuple, а не наоборот.Наследование от базового класса namedtuple - Python

В нормальном наследовании, это работает:

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> 

Но если BaseClass является 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? Так ли, как?

ответ

12

Вы можете, но вы должны переопределить __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] 
+0

Могу ли я сделать 'self.append (г)'? – alvas

+0

@alvas Нет, потому что 'namedtuple' - это в основном' tuple' (неизменный по дизайну и поэтому не имеет 'append') – MSeifert

+0

@Mseifert Спасибо! Но = ( – alvas

3

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

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)