Por que "mypy" considera "int" como um subtipo de "float"? Um subtipo deve suportar todos os métodos de seu supertipo, mas "float" possui métodos que "int" não suportam:
test.py:
def f(x : float) -> bool:
return x.is_integer()
print(f(123.0))
print(f(123))
O verificador de tipo estático aceita passar um argumento "int" para um parâmetro "float":
(3.8.1) myhost% mypy test.py
Success: no issues found in 1 source file
Mas isso não garante que não haja erros no tempo de execução:
(3.8.1) myhost% python test.py
True
Traceback (most recent call last):
File "test.py", line 5, in <module>
print(f(123))
File "test.py", line 2, in f
return x.is_integer()
AttributeError: 'int' object has no attribute 'is_integer'
porque "float" possui métodos adicionais, os quais "int" não possui.
int
não pode caber em um carro alegórico. Pythonint
s não são máquinasint
s. (De qualquer forma, não tenho certeza de como isso seria relevante para a verificação de tipo, que não está realmente preocupada com representações de tipos em tempo de execução.)int
efloat
parece ignorar completamente o fato de que ambos os tipos têm métodos, ou pelo menos métodos diferentes de__add__
et al.Respostas:
'Por que "mypy" considera "int" como um subtipo de "float"?
Porque a praticidade até agora tem sido considerada para vencer a pureza aqui. Isso não quer dizer que não se possa propor que a digitação defina um tipo escalar que inclua ints e floats, mas seja válido apenas para operações aritméticas.
Observe que int / int foi alterado no 3.0 para que float (int / int) == float (int) / float (int), para tornar a aritmética de int e float consistente para valores int e float iguais.
Observe também que uma aprovação de verificação de tipo não significa que não haja erros de tempo de execução: a divisão por zero e o estouro ainda são possíveis, assim como muitos outros.
fonte
Como @ juanpa.arrivillaga apontou, a explicação está em https://mypy.readthedocs.io/en/latest/duck_type_compatibility.html .
int
não é um subtipo defloat
, portanto, não precisa suportar métodos defloat
.O mecanismo é bom porque a passagem de valores inteiros não deve causar erros, a menos que você realmente os queira, como no seu exemplo. Você tentou explicitamente usar um método que não existe. Em situações comuns, apenas fazemos operações aritméticas em números, portanto, um problema raramente existe e você sempre pode evitá-lo adicionando
.0
como escreveu.É um comportamento comum na maioria dos idiomas assumir que esse
int
é um caso especialfloat
, considere, por exemplo, C ++int
parafloat
conversão implícita.fonte