Invalid index type "Union[int, str]" for "Union[List[Any], Dict[Any, Any]]"; expected type "int"

Viewed 2187

I had a little fight with mypy recently. Let's say i have a variable which can be a dict or a list (here self.my_list). Later, in a function (here: get), I want to access a value in this list or dict.

from typing import Union, Any

class my_class:
    def __init__(self, whatever: Union[list, dict]):
        self.my_list: Union[list, dict] = whatever

    def get(self, key: Union[int, str]) -> Any:
        return self.my_list[key]

Mypy gaves me the following error for the line where I try to access a value in my_list:

 Invalid index type "Union[int, str]" for "Union[List[Any], Dict[Any, Any]]"; expected type "int"
  • Someone has any idea how to handle this error ?
  • Is it maybe bad from start to have a variable which can be a dict or a list ?
1 Answers

mypy is not wrong in that error. Consider this case:

  • my_list is a list. This satisfies the Union[list, dict] type.
  • key is a str. This satisfies the Union[int, str] type.

However, my_list[key] is wrong, because you can't index a list with a string. When dealing with Union types, mypy will check that the code works for every combination of types within Unions, and throw an error if any combination fails.

In general I don't think your current APIs show a good design. my_list is an internal attribute, its type is an implementation detail, and should not affect usage of your class. However, you're now forcing the user to remember (or worse, dynamically check) whether they have a list or a dict stored in the class, and potentially use different keys. To me, this is either unnecessary wrapping (putting things in a class where it's perfectly fine to use them directly) or improper encapsulation (the class exposing too many implementation details or deferring its responsibilities to the user).

Related