0

I have this code:

def my_foo(x: dict[str, int | float], some_condition: bool) -> None:
    if some_condition:
        x['the_int'] = 1
    else:
        x['the_float'] = 1.0

my_dict = {'some_int': 2}

my_foo(my_dict, True)

Mypy (understandably) complains

error: Argument 1 to "my_foo" has incompatible type "dict[str, int]"; expected "dict[str, int | float]" [arg-type] note: "Dict" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance src\type_test.py:23: note: Consider using "Mapping" instead, which is covariant in the value type

I tried do type-hint using MutableMapping but to no avail:

error: Argument 1 to "my_foo" has incompatible type "dict[str, int]"; expected "MutableMapping[str, int | float]"

4
  • This question is very common. The solution is to specify the type explicitly: my_dict: dict[str, int | float] = {'some_int': 2}. There should be a good dupe somewhere. Commented Oct 5, 2024 at 21:28
  • Slightly besides the point, but I think int | float is equivalent to float (you can pass an int anywhere a float is expected, just not vice versa) so you could simplify the annotation a bit by making it dict[str, float]. You do still need to explicitly annotate my_dict either way. Commented Oct 8, 2024 at 16:20
  • @Samwise Not quite, since extremely large integers don't have floating-point equivalents. Commented Oct 16, 2024 at 12:56
  • Try it out: mypy-play.net/… Commented Oct 16, 2024 at 18:41

2 Answers 2

3

D.lola's answer is preferable if you have a fixed mapping between what keys are ints and which are float. However, if you don't, you can also just tell mypy that my_dict can contain floats:

my_dict: dict[str, int | float] = {'some_int': 2}

mypy doesn't complain about this code (since it has special casing for literals) and then wont complain for further code.

Sign up to request clarification or add additional context in comments.

1 Comment

precisely, this works too, I didn't want to assume; plus x["the_int"] and x["the_float"] made me infer.
3

You can try this. Create your own dict using TypedDict. You can use dataclass as well.

This code snippet should resolve the issue.

from typing import TypedDict, Union

class MyDict(TypedDict, total=False):
    some_int: int
    the_int: int
    the_float: float


def my_foo(x: MyDict, some_condition: bool) -> None:
    if some_condition:
        x["the_int"] = 1
    else:
        x["the_float"] = 1.0


my_dict: MyDict = {"some_int": 2}

my_foo(my_dict, True)

Tested result

mypy ol.py 

Output:

Success: no issue found in 1 source file

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.