Esta pregunta es para aclarar mis dudas relacionadas con la tipificación de python.
from typing import Union class ParentClass: parent_prop = 1 class ChildA(ParentClass): child_a_prop = 2 class ChildB(ParentClass): child_b_prop = 3 def method_body(val) -> ParentClass: if val: return ChildA() else: return ChildB() def another_method() -> ChildA: return method_body(True) print(another_method().child_a_prop)En el código anterior, la herramienta de pelusa que utilicé es un error de impresión como se muestra a continuación
error: Incompatible return value type (got "ParentClass", expected "ChildA")(donde hago method_body(True) )
También configuré el tipo de devolución method_body como Union[ChildA, ChildB] . Esto dará como resultado error: Incompatible return value type (got "Union[ChildA, ChildB]", expected "ChildA")
Estoy buscando una mejor manera de hacer esto. Si alguien sabe la solución, su ayuda será muy apreciada.
mypy no realiza análisis de tiempo de ejecución, por lo que no puede adivinar que llamar a method_body con el argumento True siempre dará como resultado un objeto ChildA . Así que el error que produce tiene sentido.
Tienes que guiar a mypy de alguna manera para decirle que sabes lo que estás haciendo y que another_method hecho produce un objeto ChildA cuando se llama con el argumento True . Una es usar uncast :
from typing import cast def another_method() -> ChildA: return cast(ChildA, method_body(True))Otra es agregar una afirmación:
def another_method() -> ChildA: result = method_body(True) assert isinstance(result, ChildA) return result La diferencia entre los dos es que el cast no tiene ninguna implicación en el tiempo de ejecución. Puede considerarlo como un comentario puesto aquí para guiar a mypy en sus comprobaciones, pero la función cast solo devuelve su segundo parámetro, es decir, aquí está el cuerpo de cast :
def cast(typ, val): return val Mientras que la assert puede generar naturalmente un error AssertionError (no en ese caso obviamente, pero en general).
Naturalmente ParentClass no es compatible con ChildA ya que no todas las instancias ParentClass serán ChildA . Lo mismo ocurre con Union[ChildA, ChildB] .
Para que another_method pase la verificación de tipos, debemos proporcionarle al verificador de tipos información adicional sobre los tipos de tiempo de ejecución involucrados, es decir, que method_boy(True) siempre devolverá un ChildA , no solo una ParentClass . Esto se puede lograr usandotyping.cast :
def another_method() -> ChildA: return typing.cast(ChildA, method_body(True))