Description
Mypy treats int
as compatible with float
(and float
as compatible with complex
) even though the types aren't ordinary subtypes of each other. This is implemented via a @ducktype
class decorator that allows specifying that a class should be treated essentially as a subclass of another class, even though there is no concrete subclass relationship and even if the interfaces aren't actually fully compatible. The mypy stub for int
looks like this (a bit simplified):
@ducktype(float)
class int(... a bunch of ABCs ...):
...
This could also be useful for things like UserString
(which is like str
but not a subclass) and mock classes in tests.
At the least, we should specify int
as compatible with float
so that people won't have to write code like this:
Float = Union[int, float]
def myfunc(x: Float) -> float:
return x * 5.0 - 2.0
Of course, all stubs for built-in modules would have to use unions everywhere for floating point arguments for the above to work in practice, and I'd like to avoid that as it seems like extra complexity with little benefit. The above would not let use some float
methods for values with the union type (such as hex()
which is only defined for float
objects but not int
objects).
If using the ducktype
approach (or special casing some classes to be compatible and not making ducktype
public) all float
methods would be available, but they might fail at runtime if the actual object is an int
. I think this is reasonable since these methods are pretty rarely used.
As a bonus, the ducktype
decorator would effectively make all classes abstract, hopefully helping address the abstract vs. concrete type problem (see #12, for example).