Inheriting from a namedtuple base class

23,424

Solution 1

You can, but you have to override __new__ which is called implicitly before __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

But d will be just an independent attribute!

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

Solution 2

I think you can achieve what you want by including all of the fields in the original named tuple, then adjusting the number of arguments using __new__ as schwobaseggl suggests above. For instance, to address max's case, where some of the input values are to be calculated rather than supplied directly, the following works:

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)

Solution 3

I came here with the exact same problem, just two years later.
I personally thought that the @property decorator would fit in here better:

from collections import namedtuple

class Base:
    @property
    def computed_value(self):
        return self.a + self.b + self.c

# inherits from Base
class A(Base, namedtuple('A', 'a b c')):
    pass

cls = A(1, 2, 3)
print(cls.computed_value)
# 6
Share:
23,424
alvas
Author by

alvas

食飽未?

Updated on May 25, 2021

Comments

  • alvas
    alvas almost 3 years

    This question is asking the opposite of Inherit namedtuple from a base class in python , where the aim is to inherit a subclass from a namedtuple and not vice versa.

    In normal inheritance, this works:

    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(Z, self).__init__(a, b, c)
            self.d = d
    

    [out]:

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

    But if the baseclass is a namedtuple:

    from collections import namedtuple
    
    X = namedtuple('X', 'a b c')
    
    class Z(X):
        def __init__(self, a, b, c, d):
            super(Z, self).__init__(a, b, c)
            self.d = d
    

    [out]:

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

    The question, is it possible to inherit namedtuples as a base class in Python? Is so, how?