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]...