web-dev-qa-db-fra.com

Héritage d'une classe de base nommétuple - Python

Cette question pose le contraire de Hériter namedtuple d'une classe de base en python , où le but est d'hériter une sous-classe d'un namedtuple et non l'inverse.

En héritage normal, cela fonctionne:

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

[en dehors]:

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

Mais si la classe de base est un 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

[en dehors]:

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

La question, est-il possible d'hériter de namedtuples comme classe de base en Python? Est-ce vrai, comment?

20
alvas

Vous pouvez, mais vous devez remplacer __new__ qui est implicitement appelé avant __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

Mais d ne sera qu'un attribut indépendant!

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

Je pense que vous pouvez obtenir ce que vous voulez en incluant tous les champs dans le tuple nommé d'origine, puis en ajustant le nombre d'arguments en utilisant __new__ comme le suggère schwobaseggl ci-dessus. Par exemple, pour résoudre le cas de max, où certaines des valeurs d'entrée doivent être calculées plutôt que fournies directement, les opérations suivantes fonctionnent:

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)
7
TimH

Je suis venu ici avec exactement le même problème, seulement deux ans plus tard.
J'ai personnellement pensé que le @property le décorateur s'intégrerait mieux ici:

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
1
Jan