#python #types #type-hinting
Вопрос:
Я написал следующую функцию:
def _clean_dict(d):
return {k: v for k, v in d.items() if v is not None}
Я хочу добавить аннотации типов к функции:
def _clean_dict(d: Dict[Any, Any]) -> Dict[Any, Any]:
return {k: v for k, v in d.items() if v is not None}
Однако я хочу явно определить, что значения внутри возвращаемого словаря не могут быть None.
Есть ли способ сказать « Any
тип, кроме NoneType
» или «Все возможные значения, но None
«?
Комментарии:
1. На самом деле вы не применяете возвращаемый тип с помощью подсказки типа. Существует подсказка типа, поэтому, когда вы ссылаетесь на код из другого места, вы можете узнать, что должна возвращать функция. Тот, кто пишет код, должен убедиться, что функция возвращает соответствующее значение (если она вообще что-либо возвращает).
2. Я не спрашивал о применении этого типа. Просто хочу, чтобы аннотация явно показывала
None
, что вNoneType
значениях возвращаемого словаря не должно быть / .3. Ах, моя ошибка. Вы могли бы добавить это в качестве комментария через строку документации функции?
4. Я могу, но я действительно думаю, что должен быть способ сделать это, используя подсказку типа, точно так же, как вы можете использовать
Optional
, чтобы показать, что что-то может быть None .5. Из кода кажется очевидным, что значения не могут быть
None
, поскольку это явно указано в понимании словаря. Как говорит @MurrayW, можно было бы использовать комментарий или строку документа.
Ответ №1:
Подсказка типа Python не может исключать типы. Вы не можете исключить None
s, str
s или любой другой тип.
Единственное, что вы можете использовать, чтобы попытаться эмулировать None
исключение, — это использовать объединение и записывать каждый тип, который вы фактически используете, в словаре.
Комментарии:
1. Есть ли причина, по которой Python не может его поддерживать?
2. Следует отметить, что средства проверки типов все равно будут разрешены
None
даже при такомUnion
подходе. У Mypy естьstrict_optional
флаг для отключения этого поведения, но это делает его несовместимым с большинством существующего кода Python.3. обсуждение здесь: github.com/python/typing/issues/256
Ответ №2:
Учитывая, что вы хотите исправить типы ключей и значений при вызове функции, вы можете использовать generics, чтобы сделать это явным. Это все еще потенциально позволяет экземплярам V
быть None
, но делает намерение довольно ясным. Обратите внимание, что вы должны использовать Mapping
из-за проблем с различиями. Однако в любом случае это предпочтительнее.
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}
С помощью этого определения mypy
правильно превращает необязательные типы в необязательные.
# 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*]'