i have a bit of an understanding problem with python type annotations. Consider the following function that is used to convert a dict to a standardized format
from __future__ import annotations # needed for type annotations in > python 3.7
from typing import Dict, List, Union
class Producer(object):
pass
def normalize_producers(
producers: Dict[str, Union[Producer, List[Producer]]]
) -> Dict[str, List[Producer]]:
"""
Function to normalize producer input to have the same format
"""
normalized_dict: Dict[str, List[Producer]] = {}
for key in producers.keys():
if isinstance(producers[key], list):
normalized_dict[key] = producers[key]
else:
normalized_dict[key] = [producers[key]]
return normalized_dict
this example results in a type issue for the assignment of normalized_dict
:
Argument of type "Producer | List[Producer]" cannot be assigned to parameter "v" of type "List[Producer]" in function "__setitem__"
Type "Producer | List[Producer]" cannot be assigned to type "List[Producer]"
"Producer" is incompatible with "List[Producer]"
Argument of type "list[Producer | List[Producer]]" cannot be assigned to parameter "v" of type "List[Producer]" in function "__setitem__"
TypeVar "_T@list" is invariant
Type "Producer | List[Producer]" cannot be assigned to type "Producer"
"List[Producer]" is incompatible with "Producer"
However, when i use a temporary list, and check the type of this list, no type issues are raised:
def normalize_producers_save(
producers: Dict[str, Union[Producer, List[Producer]]]
) -> Dict[str, List[Producer]]:
"""
Function to normalize producer input to have the same format
"""
normalized_dict: Dict[str, List[Producer]] = {}
for key in producers.keys():
templist = producers[key]
if isinstance(templist, list):
normalized_dict[key] = templist
else:
normalized_dict[key] = [templist]
return normalized_dict
Does this mean, that, although I assign the values of producers
to be either of type Producer
or List[Producer]
if isinstance(producers[key], list):
does not result in producers[key]
always being of type list ? I don't understand, what the issue with the first version of the function is.
CodePudding user response:
This is a known issue in the mypy
where it does not narrow type of index expressions like dict_var[key]
. As workaround, you can use explicit variables for dictionary values:
from __future__ import annotations # needed for type annotations in > python 3.7
from typing import Dict, List, Union
class Producer(object):
pass
def normalize_producers(
producers: Dict[str, Union[Producer, List[Producer]]]
) -> Dict[str, List[Producer]]:
"""
Function to normalize producer input to have the same format
"""
normalized_dict: Dict[str, List[Producer]] = {}
for key, value in producers.items():
if isinstance(value, list):
normalized_dict[key] = value
else:
normalized_dict[key] = [value]
return normalized_dict