Home > Enterprise >  Python Type Annotation Understanding Problem
Python Type Annotation Understanding Problem

Time:11-09

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
  • Related