Optional[...]
- это сокращенное обозначение Union[..., None]
, говорящее средству проверки типов, что либо требуется объект определенного типа, либо None
требуется. ...
обозначает любую допустимую подсказку типа , включая сложные составные типы или Union[]
несколько типов. Всякий раз, когда у вас есть аргумент ключевого слова со значением по умолчанию None
, вы должны использовать Optional
.
Итак, для ваших двух примеров у вас есть типы контейнеров dict
и list
, но значение по умолчанию для a
аргумента ключевого слова показывает, что None
это также разрешено, поэтому используйте Optional[...]
:
from typing import Optional
def test(a: Optional[dict] = None) -> None:
def test(a: Optional[list] = None) -> None:
Обратите внимание, что технически нет разницы между использованием Optional[]
в Union[]
или просто добавлением None
в Union[]
. Так Optional[Union[str, int]]
и Union[str, int, None]
есть в точности то же самое.
Лично я бы всегда придерживался использования Optional[]
при установке типа аргумента ключевого слова, который используется = None
для установки значения по умолчанию, это None
лучше документирует причину, почему это разрешено. Более того, это упрощает перемещение Union[...]
части в псевдоним отдельного типа или последующее удаление Optional[...]
части, если аргумент становится обязательным.
Например, скажем, у вас есть
from typing import Optional, Union
def api_function(optional_argument: Optional[Union[str, int]] = None) -> None:
"""Frob the fooznar.
If optional_argument is given, it must be an id of the fooznar subwidget
to filter on. The id should be a string, or for backwards compatibility,
an integer is also accepted.
"""
то документация улучшается путем вытаскивания Union[str, int]
псевдонима типа:
from typing import Optional, Union
SubWidgetId = Union[str, int]
def api_function(optional_argument: Optional[SubWidgetId] = None) -> None:
"""Frob the fooznar.
If optional_argument is given, it must be an id of the fooznar subwidget
to filter on. The id should be a string, or for backwards compatibility,
an integer is also accepted.
"""
Рефакторинг для Union[]
преобразования псевдонима стал намного проще, потому что Optional[...]
он использовался вместо Union[str, int, None]
. В None
конце концов, значение не является «идентификатором субвиджета», оно не является частью значения, None
оно предназначено для обозначения отсутствия значения.
Боковое примечание: если ваш код не должен поддерживать только Python 3.9 или новее, вам следует избегать использования стандартных библиотечных типов контейнеров в подсказках типов, поскольку вы не можете ничего сказать о том, какие типы они должны содержать. Таким образом , вместо dict
и list
, использования typing.Dict
и typing.List
, соответственно. И при чтении только из контейнерного типа вы можете с тем же успехом принять любой неизменяемый абстрактный тип контейнера; списки и кортежи являются Sequence
объектами, а dict
это Mapping
тип:
from typing import Mapping, Optional, Sequence, Union
def test(a: Optional[Mapping[str, int]] = None) -> None:
"""accepts an optional map with string keys and integer values"""
def test(a: Optional[Sequence[Union[int, str]]] = None) -> None:
"""accepts an optional sequence of integers and strings
# print(a) ==> [1, 2, 3, 4, 'a', 'b']
# or
# print(a) ==> None
В Python 3.9 и выше все стандартные типы контейнеров были обновлены для поддержки использования их в подсказках типов, см. PEP 585 . Но , хотя теперь вы можете использовать dict[str, int]
или list[Union[int, str]]
, вы все равно можете использовать более выразительные Mapping
и Sequence
аннотации, чтобы указать, что функция не будет изменять содержимое (они обрабатываются как `` только для чтения '') и что функции будут работать с любой объект, который работает как отображение или последовательность соответственно.
Dict
иList
печатать, и писать,Optional[Dict]
иOptional[List]
вместоOptional[dict]
...list
иdict
быть используем для подсказок типа, ( по сравнению сList
,Dict
). python.org/dev/peps/pep-0585Непосредственно из документации модуля mypy typing .
источник