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 dict
i list
, ale domyślna wartość a
argumentu słowa kluczowego pokazuje, że None
jest 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 None
do 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 = None
do ustawiania wartości domyślnej, to dokumentuje powód, dla którego None
jest 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 None
koń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 dict
i list
, użytkowania typing.Dict
i typing.List
odpowiednio. Czytając tylko z typu kontenera, równie dobrze możesz zaakceptować dowolny niezmienny abstrakcyjny typ kontenera; listy i krotki są Sequence
obiektami, a dict
jest Mapping
typem:
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 Mapping
i Sequence
adnotacje, 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.
Dict
iList
od pisania i pisaćOptional[Dict]
iOptional[List]
zamiastOptional[dict]
...list
idict
może być używane do podpowiedzi typu (vs.List
,Dict
). python.org/dev/peps/pep-0585Bezpośrednio z mypy typing module docs .
źródło