Cambiar el tipo de parámetro de miembro para la sugerencia de tipo de

Cambiar el tipo de parámetro de miembro para la sugerencia de tipo de python

Tengo un código como este:

class A:
    def __init__(self, a: int) -> None:
        self.a: int = a


class B(A):
    def __init__(self, a: float) -> None:
        self.a: float = a

El problema es que self.a cambia de tipo int en la clase base, A, a float en la clase B. mypy me da este error:

typehintancestor.py:8: error: Incompatible types in assignment (expression has type "float", variable has type "int")

(La línea 8 es la última línea)

¿Es esto un error en mypy o debo cambiar la implementación de la clase B?

Mostrar la mejor respuesta

Yo diría que es un error en mypy. B es libre de ocultar a y anular __init__, como lo ha hecho aquí. Un error legítimo sería si usara A.__init__(self, a), que intentaría pasar su float a una función que espera un int. (Estoy ignorando a propósito lo que hace/debe hacer mypy con una llamada a super).

Dicho de otra manera, B puede heredar A.__init__, pero no lo está usando aquí.

@chepner No creo que sea un error, se considera un error sobrecargar la firma del método de una subclase (incluso los tipos) ya que rompe la covarianza. Dicho esto, no estoy seguro de estar de acuerdo con esa conclusión.

Punto justo; si tengo un objeto x: List[a], debería poder asumir que x[0].a es un int, si x[0] es una instancia de A o una subclase de A.

Este es un error en su código. Supongamos que fuera legal definir sus clases de esa manera y escribimos el siguiente programa:

from typing import List

# class definitions here

def extract_int(items: List[A]) -> List[int]:
    return [item.a for item in items]

my_list: List[A] = [A(1), A(2), B(3.14)]
list_of_ints = extract_int(my_list)

Esperamos que la variable list_of_ints contenga solo ints, pero en realidad contendrá un flotante.

Básicamente, mypy exige que su código siga el principio de sustitución de Liskov aquí.