Skip to content

Improve duck type compatibility of int with float #100268

Closed
@JakubTesarek

Description

@JakubTesarek

Feature or enhancement

Function arguments and variables annotated with float should not allow value of type int.

Pitch

PEP484 suggested that when an argument is annotated as having type float, an argument of type int is acceptable;. This allows this kind of typing to be valid:

x: float = 2

But int is not subtype of float and doesn't provide the same interface. Float provides methods that are not available in int:

  • is_integer
  • fromhex
  • hex

This violates LSP and is problematic especially with is_integer:

def method_requiring_whole_number_float(number: float):
    if number.is_integer():
        ...

This method clearly states that it requires float and as an author of such code, I would expect that is_integer would be available if my typing is correct.

There are workarounds (if int(number) == number:) but they render the is_integer useless as it can never be safely used.

Just adding the missing methods to int (or removing the extra methods from float) would not be valid solution as there are other problems stemming from the fact that int is not float. Eg.:

def split_whole_and_decimal(number: float) -> tuple[str, str]:
    return str(number).split('.')  # it's reasonable to expect that the output contains a dot `.` as  `float` does but `int` doesn't 

I'm proposing an errata to PEP484 that will remove when an argument is annotated as having type float, an argument of type int is acceptable;.

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions