Optional[...]jest skrótową notacją Union[..., None]informującą moduł sprawdzania typów, że obiekt określonego typu jest wymagany lub None jest wymagany. ...oznacza każdą prawidłową wskazówkę dotyczącą typu , w tym złożone typy złożone lub aUnion[] więcej typów. Zawsze, gdy masz argument słowa kluczowego z wartością domyślną None, powinieneś użyć Optional.
W dwóch przykładach masz typy kontenerów dicti list, ale domyślna wartość aargumentu słowa kluczowego pokazuje, że Nonejest to również dozwolone, więc użyjOptional[...] :
from typing import Optional
def test(a: Optional[dict] = None) -> None:
def test(a: Optional[list] = None) -> None:
Zauważ, że nie ma technicznej różnicy między używaniem Optional[]na a Union[]lub po prostu dodawaniem Nonedo Union[]. Więc Optional[Union[str, int]]i Union[str, int, None]są dokładnie tym samym.
Osobiście wolałbym zawsze używać Optional[]podczas ustawiania typu argumentu słowa kluczowego używanego = Nonedo ustawiania wartości domyślnej, to dokumentuje powód, dla którego Nonejest lepiej dozwolony. Ponadto ułatwia przeniesienie Union[...]części do oddzielnego aliasu typu lub późniejsze usunięcie Optional[...]części, jeśli argument stanie się obowiązkowy.
Na przykład powiedz, że masz
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.
"""
następnie dokumentacja jest ulepszana poprzez wyciągnięcie Union[str, int]do aliasu typu:
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.
"""
Refaktoryzacja przenoszenia Union[]do aliasu została znacznie łatwiejsza, ponieważ Optional[...]została użyta zamiastUnion[str, int, None] . W Nonekońcu wartość nie jest „identyfikatorem subwidgetu”, nie jest częścią wartości,None jest przeznaczona do flaga braku wartości.
Uwaga boczna: O ile twój kod nie musi obsługiwać tylko Pythona 3.9 lub nowszego, chcesz uniknąć używania standardowych typów kontenerów bibliotek w podpowiedziach typu, ponieważ nie możesz nic powiedzieć o tym, jakie typy muszą zawierać. Więc zamiast dicti list, użytkowania typing.Dicti typing.Listodpowiednio. Czytając tylko z typu kontenera, równie dobrze możesz zaakceptować dowolny niezmienny abstrakcyjny typ kontenera; listy i krotki są Sequenceobiektami, a dictjest Mappingtypem:
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
W Pythonie 3.9 i nowszych wszystkie standardowe typy kontenerów zostały zaktualizowane, aby obsługiwały ich używanie we wskazówkach dotyczących typów, patrz PEP 585 . Ale teraz możesz używaćdict[str, int] albo list[Union[int, str]], nadal może chcieć użyć bardziej wyraziste Mappingi Sequenceadnotacje, aby wskazać, że funkcja nie będzie mutacji zawartość (są one traktowane jako „tylko do odczytu”), oraz że funkcje będą pracować z dowolny obiekt, który działa odpowiednio jako odwzorowanie lub sekwencja.
DictiListod pisania i pisaćOptional[Dict]iOptional[List]zamiastOptional[dict]...