polimorfismo - Herencia mĂșltiple en python3 con diferentes firmas
subclases python (1)
No use super(baseclass, ...)
menos que sepa lo que está haciendo. El primer argumento de super()
le dice qué clase omitir cuando se busca el siguiente método a usar. Por ejemplo, super(A, ...)
mirará el MRO, encontrará A
y luego comenzará a buscar __init__
en la siguiente clase de base, no A
sí. Para C
, el MRO es (C, A, B, object)
, por lo que super(A, self).__init__
encontrará B.__init__
.
Para estos casos, no desea utilizar la herencia cooperativa, sino que haga referencia directamente a A.__init__
y B.__init__
. super()
solo se debe usar si los métodos a los que llama tienen la misma firma o **vargs
argumentos no compatibles con *args
y **vargs
. En ese caso, solo se necesitaría una llamada super(C, self).__init__()
y la siguiente clase en la orden MRO se encargaría de encadenar la llamada.
Poniéndolo de manera diferente: cuando usas super()
, no puedes saber qué clase será la siguiente en el MRO, por lo que esa clase soporta mejor los argumentos que le pasas. Si ese no es el caso, no use super()
.
Llamando a los métodos base __init__
directamente:
class A(object):
def __init__(self, a, b):
print(''Init {} with arguments {}''.format(self.__class__.__name__, (a, b)))
class B(object):
def __init__(self, q):
print(''Init {} with arguments {}''.format(self.__class__.__name__, (q)))
class C(A, B):
def __init__(self):
# Unbound functions, so pass in self explicitly
A.__init__(self, 1, 2)
B.__init__(self, 3)
Usando cooperativo super()
:
class A(object):
def __init__(self, a=None, b=None, *args, **kwargs):
super().__init__(*args, **kwargs)
print(''Init {} with arguments {}''.format(self.__class__.__name__, (a, b)))
class B(object):
def __init__(self, q=None, *args, **kwargs):
super().__init__(*args, **kwargs)
print(''Init {} with arguments {}''.format(self.__class__.__name__, (q)))
class C(A, B):
def __init__(self):
super().__init__(a=1, b=2, q=3)
Tengo tres clases: A
, B
y C
C
hereda de A
y B
(en este orden). Las firmas constructoras de A
y B
son diferentes. ¿Cómo puedo llamar a los métodos __init__
de ambas clases para padres?
Mi esfuerzo en el código:
class A(object):
def __init__(self, a, b):
super(A, self).__init__()
print(''Init {} with arguments {}''.format(self.__class__.__name__, (a, b)))
class B(object):
def __init__(self, q):
super(B, self).__init__()
print(''Init {} with arguments {}''.format(self.__class__.__name__, (q)))
class C(A, B):
def __init__(self):
super(A, self).__init__(1, 2)
super(B, self).__init__(3)
c = C()
produce el error:
Traceback (most recent call last):
File "test.py", line 16, in <module>
c = C()
File "test.py", line 13, in __init__
super(A, self).__init__(1, 2)
TypeError: __init__() takes 2 positional arguments but 3 were given
Encontré este recurso que explica la herencia múltiple con diferentes conjuntos de argumentos, pero sugieren utilizar *args
y **kwargs
para usar para todos los argumentos. Considero que esto es muy feo, ya que no puedo ver en la clase del constructor en la clase secundaria qué tipo de parámetros transfiero a las clases primarias.