La herencia de Generic y NamedTuple falla con el error “falta el argumento posicional requerido”.
Me he encontrado con un problema al intentar definir un NamedTuple
genérico (typing/mypy Generic
). He logrado reducirlo al ejemplo de trabajo más pequeño posible:
a.py:
from typing import NamedTuple
from typing import Generic
from typing import TypeVar
T = TypeVar('T')
class A(Generic[T], NamedTuple('A', [('x', T)])):
pass
a = A(12)
Esto funciona perfectamente en todas las versiones de Python que tenemos que admitir (incluyendo 3.4, 3.7), excepto en la versión 3.5.3, donde falla:
$ python3 a.py
Traceback (most recent call last):
File "a.py", line 10, in <module>
a = A(12)
File "/usr/lib/python3.5/typing.py", line 1126, in __new__
return _generic_new(cls.__next_in_mro__, cls, *args, **kwds)
File "/usr/lib/python3.5/typing.py", line 1087, in _generic_new
return base_cls.__new__(cls)
TypeError: __new__() missing 1 required positional argument: 'x'
He intentado agregar manualmente el método __new__
:
class A(Generic[T], NamedTuple('A', [('x', T)])):
def __new__(cls, a):
return super(A, cls).__new__(cls, a)
pero falla con exactamente el mismo mensaje de error.
Nombrar explícitamente el parámetro x
(a = A(x=12)
) también arroja el mismo mensaje de error.
¿Hay alguna manera de hacer que funcione?
Por favor, no me digas que actualice Python, ya que admitimos varias versiones de Python y 3.5.3 es una de ellas. Actualizar Python no es una opción aquí.
davy.ai
Parece que la causa del error es la implementación de la clase
NamedTuple
en Python 3.5.3. Una solución temporal para este problema podría ser definir el método__init__
en la claseA
y llamar al métodosuper().__init__()
con el argumentox
pasado como una tupla:Esto debería funcionar tanto en Python 3.5.3 como en otras versiones. Sin embargo, ten en cuenta que al definir manualmente
__init__
, no obtendremos la implementación por defecto de__new__
que proporcionaNamedTuple
. Por lo tanto, si queremos realizar personalizaciones adicionales en el proceso de instanciación, también deberemos definir nuestra propia implementación de__new__
.