Optional[...]
es una notación abreviada para Union[..., None]
decirle al verificador de tipos que se requiere o None
se requiere un objeto del tipo específico . ...
significa cualquier sugerencia de tipo válida , incluidos los tipos compuestos complejos o a Union[]
de más tipos. Siempre que tenga un argumento de palabra clave con un valor predeterminado None
, debe usar Optional
.
Entonces, para sus dos ejemplos, tiene tipos de contenedor dict
y list
, pero el valor predeterminado para el a
argumento de palabra clave muestra que también None
está permitido, así que use Optional[...]
:
from typing import Optional
def test(a: Optional[dict] = None) -> None:
def test(a: Optional[list] = None) -> None:
Tenga en cuenta que técnicamente no hay diferencia entre usar Optional[]
en a Union[]
, o simplemente agregar None
a Union[]
. Entonces Optional[Union[str, int]]
y Union[str, int, None]
son exactamente lo mismo.
Personalmente, me quedaría con el uso siempreOptional[]
al configurar el tipo de un argumento de palabra clave que se usa = None
para establecer un valor predeterminado, esto documenta la razón por la que None
se permite mejor. Además, hace que sea más fácil mover la Union[...]
parte a un alias de tipo separado, o eliminar posteriormente la Optional[...]
parte si un argumento se vuelve obligatorio.
Por ejemplo, digamos que tienes
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.
"""
luego la documentación se mejora al extraer el Union[str, int]
en un alias de tipo:
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.
"""
El refactor para mover el Union[]
a un alias se hizo mucho más fácil porque Optional[...]
se usó en lugar de Union[str, int, None]
. El None
valor no es un 'ID de subwidget' después de todo, no es parte del valor, None
está destinado a marcar la ausencia de un valor.
Nota al margen: a menos que su código solo sea compatible con Python 3.9 o más reciente, desea evitar el uso de los tipos de contenedor de biblioteca estándar en las sugerencias de tipo, ya que no puede decir nada sobre qué tipos deben contener. Entonces, en lugar de dict
y list
, use typing.Dict
y typing.List
, respectivamente. Y cuando solo lee de un tipo de contenedor, también puede aceptar cualquier tipo de contenedor abstracto inmutable; las listas y tuplas son Sequence
objetos, mientras que dict
es un Mapping
tipo:
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
En Python 3.9 y versiones posteriores, todos los tipos de contenedores estándar se han actualizado para admitir su uso en sugerencias de tipo, consulte PEP 585 . Pero , aunque ahora puede usar dict[str, int]
o list[Union[int, str]]
, es posible que desee usar las anotaciones Mapping
y más expresivas Sequence
para indicar que una función no mutará el contenido (se tratan como 'solo lectura'), y que las funciones funcionarían con cualquier objeto que funcione como mapeo o secuencia, respectivamente.
Dict
yList
de escribir y escribirOptional[Dict]
y enOptional[List]
lugar deOptional[dict]
...?list
ydict
puede usarse para sugerencias de tipo, (vs.List
,Dict
). python.org/dev/peps/pep-0585Directamente desde los documentos del módulo de mecanografía mypy .
fuente