Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a type hint `float` accept `int` while it is not even a subclass?

On the one hand, I have learned that numbers that can be int or float should be type annotated as float (sources: PEP 484 Type Hints and this stackoverflow question):

def add(a: float, b: float):
    return a + b

On the other hand, an int is not an instance of float:

  • issubclass(int, float) returns False
  • isinstance(42, float) returns False

I would thus have expected Union[int, float] to be the correct annotation for this use case.

Questions:

  • What is the reason for that counter-intuitive behaviour? Does type hinting follow different mechanics than class comparisons (for instance in some case a "lossless casting" rule or so)?
  • Are int/float a special case in type annotations? Are there other examples like this?
  • Is there any linter that would warn me about Union[float, int] if this is an unintended use?
like image 394
matheburg Avatar asked Jul 04 '20 05:07

matheburg


People also ask

Is int a subclass of float?

On the other hand, an int is not an instance of float : issubclass(int, float) returns False. isinstance(42, float) returns False.

Should you use type hints in Python?

In his excellent article The State of Type Hints in Python Bernát Gábor recommends that “type hints should be used whenever unit tests are worth writing.” Indeed, type hints play a similar role as tests in your code: they help you as a developer write better code.

What is type hinting in Python?

Type hinting is a formal solution to statically indicate the type of a value within your Python code. It was specified in PEP 484 and introduced in Python 3.5.

Does Python enforce type hints?

New in version 3.5. The Python runtime does not enforce function and variable type annotations. They can be used by third party tools such as type checkers, IDEs, linters, etc.


1 Answers

  • Are int/float a special case in type annotations?

float is a special case. int is not. PEP 484 says, in the paragraph below the one referenced by the link in your question:

when an argument is annotated as having type float, an argument of type int is acceptable;

So accepting int where float is annotated is explicitly a special case, independent of the way annotations generally deal with a class hierarchy.

Are there other examples like this?

Yes, there's at least one other special case. In that same paragraph PEP 484 goes on to say:

for an argument annotated as having type complex, arguments of type float or int are acceptable.

  • Is there any linter that would warn me about Union[float, int] if this is an unintended use?

Union[float, int] is perfectly fine.

The special treatment of a float annotation is just a convenience (PEP 484 calls it a "shortcut") to allow people to avoid writing out the long-winded Union[float, int] annotation, because arguments that can be a float or an int are very common.

like image 74
ottomeister Avatar answered Oct 23 '22 05:10

ottomeister