Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exclude type in Python typing annotation

I wrote the following function:

def _clean_dict(d):
    return {k: v for k, v in d.items() if v is not None}

I want to add type annotations to the function:

def _clean_dict(d: Dict[Any, Any]) -> Dict[Any, Any]:                           
    return {k: v for k, v in d.items() if v is not None}

However, I want to explicitly define that the values inside the returned dictionary cannot be None.

Is there a way to say "Any type, except NoneType" or "Every possible value but None"?

like image 287
Yam Mesicka Avatar asked Sep 09 '19 13:09

Yam Mesicka


2 Answers

Given that you are willing to fix the types of keys and values when the function is called you can use generics to make this explicit. This still potentially allows instances of V to be None, but it makes the intent pretty clear. Note that you have to use Mapping because of variance issues. However, this is preferable anyway.

from typing import *


K = TypeVar("K")
V = TypeVar("V")


def _clean_dict(d: Mapping[K, Optional[V]]) -> MutableMapping[K, V]:
    return {k: v for k, v in d.items() if v is not None}

With this definition mypy correctly turns optional into non-optional types.

# clean_dict.py

d = {"a": 1, "b": 2, "c": None}
reveal_type(d)
reveal_type(_clean_dict(d))

$ mypy clean_dict.py

note: Revealed type is 'builtins.dict[builtins.str*, Union[builtins.int, None]]'
note: Revealed type is 'typing.MutableMapping[builtins.str*, builtins.int*]'

like image 129
Jarno Avatar answered Oct 19 '22 19:10

Jarno


Python type hinting can't exclude types. You can't exclude Nones, strs or any another type.

The only thing you can use to try to emulate None exclusion is to use Union and write every type you are actually using in the dictionary.

like image 27
vurmux Avatar answered Oct 19 '22 19:10

vurmux