python_user_1234
python_user_1234

Reputation: 161

mypy: Why is "int" a subtype of "float"?

Why does "mypy" consider "int" as a subtype of "float"? A subtype shall support all methods of its supertype, but "float" has methods, which "int" does not support:

test.py:

def f(x : float) -> bool:
    return x.is_integer()

print(f(123.0))
print(f(123))

The static type checker accepts passing an "int" argument for a "float" parameter:

(3.8.1) myhost% mypy test.py
Success: no issues found in 1 source file

But this does not guarantee, that there are no errors at runtime:

(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'

because "float" has additional methods, which "int" does not have.

Upvotes: 14

Views: 2637

Answers (2)

Terry Jan Reedy
Terry Jan Reedy

Reputation: 19209

'Why does "mypy" consider "int" as a subtype of "float"?'

Because practicality has so far been considered to beat purity here. This is not to say that one could not propose that typing define a Scalar type that would include ints and floats but only be valid for arithmetic operations.

Note that int / int was changed in 3.0 so that float(int / int) == float(int) / float(int), to make int and float arithmetic consistent for equal int and float values.

Note also that a type-check passing does not mean no runtime errors: division by zero and overflow are still possible, as well as many others.

UPDATE: as of Python 3.8, ints now have an .as_integer_ratio method, and as of 3.12, ints will gain an .is_integer method, leaving only the specialized .hex and .from_hex as float-only.

Upvotes: 5

camilajenny
camilajenny

Reputation: 5054

As @juanpa.arrivillaga pointed out, the explanation is on https://mypy.readthedocs.io/en/latest/duck_type_compatibility.html.

A subtype shall support all methods of its supertype, but "float" has methods, which "int" does not support

int is not a subtype of float, so it doesn't have to support methods of float.

The mechanism is good because passing integer values shouldn't cause errors, unless you really want them as in your example. You explicitly tried to use a method which doesn't exist. In common situations, we only make arithmetic operations on numbers, so a problem rarely exists and you can always avoid it by adding .0 as you wrote.

It is a common behavior in most languages to assume that int is a special case of float, consider for example C++ int to float implicit conversion.

Upvotes: -2

Related Questions