diff --git a/docs/es/docs/python-types.md b/docs/es/docs/python-types.md
index e9fd61629..43a2ea4d1 100644
--- a/docs/es/docs/python-types.md
+++ b/docs/es/docs/python-types.md
@@ -1,12 +1,12 @@
# Introducción a los Tipos de Python
-**Python 3.6+** tiene soporte para "type hints" opcionales.
+Python tiene soporte para "type hints" opcionales (también se conocido como "type annotations").
-Estos **type hints** son una nueva sintáxis, desde Python 3.6+, que permite declarar el tipo de una variable.
+Estos **type hints** o anotaciones son una sintáxis especial que permite declarar el tipo de una variable.
-Usando las declaraciones de tipos para tus variables, los editores y otras herramientas pueden proveerte un soporte mejor.
+Usando las declaraciones de tipos para tus variables, los editores y herramientas pueden proveerte un soporte mejor.
-Este es solo un **tutorial corto** sobre los Python type hints. Solo cubre lo mínimo necesario para usarlos con **FastAPI**... realmente es muy poco lo que necesitas.
+Este es solo un **tutorial corto** sobre los Python type hints. Solo cubre lo mínimo necesario para usarlos con **FastAPI**... que actualmente es muy poco.
Todo **FastAPI** está basado en estos type hints, lo que le da muchas ventajas y beneficios.
@@ -49,7 +49,7 @@ En algún punto habrías comenzado con la definición de la función, tenías lo
Pero, luego tienes que llamar "ese método que convierte la primera letra en una mayúscula".
-Era `upper`? O era `uppercase`? `first_uppercase`? `capitalize`?
+Cómo era `upper`? O era `uppercase`? `first_uppercase`? `capitalize`?
Luego lo intentas con el viejo amigo de los programadores, el autocompletado del editor.
@@ -144,57 +144,101 @@ Por ejemplo, puedes usar:
{!../../../docs_src/python_types/tutorial005.py!}
```
-### Tipos con sub-tipos
+### Tipos genéricos con argumentos de tipo
Existen algunas estructuras de datos que pueden contener otros valores, como `dict`, `list`, `set` y `tuple`. Los valores internos pueden tener su propio tipo también.
-Para declarar esos tipos y sub-tipos puedes usar el módulo estándar de Python `typing`.
+Estos tipos que tienen tipos internos se denominan tipos "**genéricos**". Es posible declararlos, incluso con sus tipos internos.
-Él existe específicamente para dar soporte a este tipo de type hints.
+Para declarar esos tipos y sub-tipos puedes usar el módulo estándar de Python `typing`.Él existe específicamente para dar soporte a este tipo de type hints.
+
+#### Nuevas versiones de Python
+
+La sintaxis que usa `typing` es **compatible** con todas las versiones, desde Python 3.6 hasta las más recientes, incluidas Python 3.9, Python 3.10, etc.
+
+A medida que avanza Python, las **versiones más nuevas** vienen con soporte mejorado para estas anotaciones de tipo y en muchos casos ni siquiera necesitarás importar y usar el módulo `typing` para declarar las anotaciones de tipo.
+
+Si puedes elegir una versión más reciente de Python para tu proyecto, podrás aprovechar esa simplicidad adicional.
+
+En toda la documentación hay ejemplos compatibles con cada versión de Python (cuando existan diferencias).
+
+Por ejemplo, "**Python 3.6+**" significa que es compatible con Python 3.6 o superior (incluidos 3.7, 3.8, 3.9, 3.10, etc.). Y "**Python 3.9+**" significa que es compatible con Python 3.9 o superior (incluido 3.10, etc.).
+
+Si puede utilizar las **últimas versiones de Python**, utilice los ejemplos de la última versión, que tendrán la **mejor y más simple sintaxis**, por ejemplo, "**Python 3.10+**".
#### Listas
Por ejemplo, vamos a definir una variable para que sea una `list` compuesta de `str`.
-De `typing`, importa `List` (con una `L` mayúscula):
+=== "Python 3.9+"
-```Python hl_lines="1"
-{!../../../docs_src/python_types/tutorial006.py!}
-```
+ Declara la variable con la misma sintáxis de los dos puntos (`:`).
-Declara la variable con la misma sintáxis de los dos puntos (`:`).
+ Como tipo, pon `list`.
-Pon `List` como el tipo.
+ Como la lista es un tipo que contiene algunos tipos internos, colócalos entre corchetes `[]`:
-Como la lista es un tipo que permite tener un "sub-tipo" pones el sub-tipo en corchetes `[]`:
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial006_py39.py!}
+ ```
-```Python hl_lines="4"
-{!../../../docs_src/python_types/tutorial006.py!}
-```
+=== "Python 3.8+"
-Esto significa: la variable `items` es una `list` y cada uno de los ítems en esta lista es un `str`.
+ De `typing`, importa `List` (con una `L` mayúscula):
+
+ ``` Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial006.py!}
+ ```
+
+ Declara la variable con la misma sintáxis de los dos puntos (`:`).
+
+ Como tipo, pon la `List` importada desde typing`.
+
+ Como la lista es un tipo que contiene algunos tipos internos, colócalos entre corchetes `[]`:
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/python_types/tutorial006.py!}
+ ```
+
+!!! info "Información"
+ Estos tipos internos entre corchetes se denominan "argumentos de tipo".
+
+ En este caso `str` es un argumentos de tipo pasado a la `List` (or `list` in Python 3.9 and above).
+
+Esto significa: "la variable `items` es una `list`, y cada uno de los ítems en esa lista es un `str`".
+
+!!! tip "Consejo"
+ Si estas utilizando 3.9 o superior, no tienes que importar `List` desde `typing`, puedes utilizar `list` en su defecto.
Con esta declaración tu editor puede proveerte soporte inclusive mientras está procesando ítems de la lista.
-Sin tipos el autocompletado en este tipo de estructura es casi imposible de lograr:
-
+Sin tipos el autocompletado en este tipo de estructura es casi imposible de lograr:
+
Observa que la variable `item` es unos de los elementos en la lista `items`.
El editor aún sabe que es un `str` y provee soporte para ello.
-#### Tuples y Sets
+#### Tuplas y Sets
Harías lo mismo para declarar `tuple`s y `set`s:
-```Python hl_lines="1 4"
-{!../../../docs_src/python_types/tutorial007.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial007_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial007.py!}
+ ```
Esto significa:
-* La variable `items_t` es un `tuple` con 3 ítems, un `int`, otro `int`, y un `str`.
+* La variable `items_t` es una `tuple` con 3 ítems, un `int`, otro `int`, y un `str`.
* La variable `items_s` es un `set` y cada uno de sus ítems es de tipo `bytes`.
#### Diccionarios (Dicts)
@@ -205,15 +249,164 @@ El primer sub-tipo es para los keys del `dict`.
El segundo sub-tipo es para los valores del `dict`:
-```Python hl_lines="1 4"
-{!../../../docs_src/python_types/tutorial008.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial008_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial008.py!}
+ ```
Esto significa:
* La variable `prices` es un `dict`:
- * Los keys de este `dict` son de tipo `str` (Digamos que son el nombre de cada ítem).
- * Los valores de este `dict` son de tipo `float` (Digamos que son el precio de cada ítem).
+ * Los keys de este `dict` son de tipo `str` (digamos que son el nombre de cada ítem).
+ * Los valores de este `dict` son de tipo `float` (digamos que son el precio de cada ítem).
+
+#### Union
+
+Puedes declarar que una variable puede ser cualquiera de **varios tipos**, por ejemplo, una `int` o una `str`.
+
+En Python 3.6 y superiores (incluido Python 3.10) puede usar el tipo `Union` de `typing` y poner entre corchetes los tipos posibles a aceptar.
+
+En Python 3.10 también hay una **nueva sintaxis** donde puedes poner los tipos posibles separados por una barra vertical (`|` ).
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial008b_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial008b.py!}
+ ```
+
+En ambos casos, esto significa que `item` podría ser un `int` o un `str`.
+
+#### Posibilidad `None`
+
+Puedes declarar que un valor podría tener un tipo, como `str`, pero que también podría ser `None`.
+
+En Python 3.6 y superior (incluido Python 3.10), puede declararlo importando y usando `Optional` desde el módulo "escribir".
+
+```Python hl_lines="1 4"
+{!../../../docs_src/python_types/tutorial009.py!}
+```
+
+Usar `Optional[str]` en lugar de solo `str` permitirá que el editor te ayude a detectar errores en los que podrías asumir que un valor es siempre una `str`, cuando en realidad también podría ser `None`.
+
+`Optional[Something]` es en realidad un atajo para `Union[Something, None]`, son equivalentes.
+
+Esto también significa que en Python 3.10, puedes usar `Something | None`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial009_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial009.py!}
+ ```
+
+=== "Python 3.8+ alternative"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial009b.py!}
+ ```
+
+#### Usar `Union` o `Optional`
+
+Si está utilizando una versión de Python inferior a 3.10, aquí tiene un consejo desde mi punto de vista muy **subjetivo**:
+
+* 🚨 Evite el uso de `Optional[SomeType]`
+* En su lugar ✨ **use `Union[SomeType, None]`** ✨.
+
+Ambos son equivalentes y en el fondo son iguales, pero recomendaría `Union` en lugar de `Optional` porque la palabra "**optional**" parecería implicar que el valor es opcional, y en realidad significa "puede ser `None`”, incluso si no es opcional y sigue siendo obligatorio.
+
+Creo que "Union[SomeType, None]" es más explícito sobre lo que significa.
+
+Se trata sólo de las palabras y los nombres. Pero esas palabras pueden afectar la forma en que usted y sus compañeros de equipo piensan sobre el código.
+
+Como ejemplo, tomemos esta función:
+
+```Python hl_lines="1 4"
+{!../../../docs_src/python_types/tutorial009c.py!}
+```
+
+El parámetro `nombre` se define como `Optional[str]`, pero **no es opcional**, no se puede llamar a la función sin el parámetro:
+
+```Python
+say_hi() # Oh, no, this throws an error! 😱
+```
+
+El parámetro `name` es **aún requerido** (no *opcional*) porque no tiene un valor predeterminado. Aún así, `name` acepta `None` como valor:
+
+```Python
+say_hi(name=None) # This works, None is valid 🎉
+```
+
+La buena noticia es que una vez que estés en Python 3.10 no tendrás que preocuparte por eso, ya que podrás simplemente usar `|` para definir uniones de tipos:
+
+```Python hl_lines="1 4"
+{!../../../docs_src/python_types/tutorial009c_py310.py!}
+```
+
+Y entonces no tendrá que preocuparse por nombres como `Optional` y `Union`. 😎
+
+#### Tipos Genéricos
+
+Estos tipos que toman parámetros de tipo entre corchetes se denominan **Tipos genéricos** o **Genéricos**, por ejemplo:
+
+=== "Python 3.10+"
+
+ Puede utilizar los mismos tipos integrados que los genéricos (con corchetes y tipos dentro):
+
+ * `list`
+ * `tuple`
+ * `set`
+ * `dict`
+
+ Y lo mismo que con Python 3.8, desde el módulo `typing`:
+
+ * `Union`
+ * `Optional` (lo mismo que con Python 3.8)
+ * ...y otros.
+
+ En Python 3.10, como alternativa al uso de los genéricos `Union` y `Optional`, puedes usar la barra vertical (`| `) para declarar uniones de tipos, eso es mucho mejor y más simple.
+
+=== "Python 3.9+"
+
+ Puede utilizar los mismos tipos integrados que los genéricos (con corchetes y tipos dentro):
+
+ * `list`
+ * `tuple`
+ * `set`
+ * `dict`
+
+ Y lo mismo que con Python 3.8, desde el módulo `typing`:
+
+ * `Union`
+ * `Optional`
+ * ...y otros.
+
+=== "Python 3.8+"
+
+ * `List`
+ * `Tuple`
+ * `Set`
+ * `Dict`
+ * `Union`
+ * `Optional`
+ * ...y otros.
### Clases como tipos
@@ -222,19 +415,23 @@ También puedes declarar una clase como el tipo de una variable.
Digamos que tienes una clase `Person`con un nombre:
```Python hl_lines="1-3"
-{!../../../docs_src/python_types/tutorial009.py!}
+{!../../../docs_src/python_types/tutorial010.py!}
```
Entonces puedes declarar una variable que sea de tipo `Person`:
```Python hl_lines="6"
-{!../../../docs_src/python_types/tutorial009.py!}
+{!../../../docs_src/python_types/tutorial010.py!}
```
Una vez más tendrás todo el soporte del editor:
+Observe que esto significa que "`one_person` es una **instance** de la clase `Person`".
+
+No significa que "`one_person` sea la **clase** llamada `Person`".
+
## Modelos de Pydantic
Pydantic es una library de Python para llevar a cabo validación de datos.
@@ -243,44 +440,98 @@ Tú declaras la "forma" de los datos mediante clases con atributos.
Cada atributo tiene un tipo.
-Luego creas un instance de esa clase con algunos valores y Pydantic validará los valores, los convertirá al tipo apropiado (si ese es el caso) y te dará un objeto con todos los datos.
+Luego creas una instance de esa clase con algunos valores y Pydantic validará los valores, los convertirá al tipo apropiado (si ese es el caso) y te dará un objeto con todos los datos.
Y obtienes todo el soporte del editor con el objeto resultante.
-Tomado de la documentación oficial de Pydantic:
+Un ejemplo de la documentación oficial de Pydantic:
-```Python
-{!../../../docs_src/python_types/tutorial010.py!}
-```
+=== "Python 3.10+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011.py!}
+ ```
!!! info "Información"
Para aprender más sobre Pydantic mira su documentación.
**FastAPI** está todo basado en Pydantic.
-Vas a ver mucho más de esto en práctica en el [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
+Vas a ver mucho más de esto en práctica en el [Tutorial - Guía de Usuario](tutorial/index.md){.internal-link target=_blank}.
-## Type hints en **FastAPI**
+!!! tip "Consejo"
+ Pydantic tiene un comportamiento especial cuando usas `Optional` o `Union[Something, None]` sin un valor predeterminado, puedes leer más sobre esto en la documentación de Pydantic acerca de Campos opcionales obligatorios.
-**FastAPI** aprovecha estos type hints para hacer varias cosas.
+## "Type Hints" con Anotaciones de Metadatos
-Con **FastAPI** declaras los parámetros con type hints y obtienes:
+Python también tiene una característica que permite poner **metadatos adicionales** en estas sugerencias de tipo usando "Annotated".
+
+=== "Python 3.9+"
+
+ En Python 3.9, `Annotated` es parte de la biblioteca estándar, por lo que puedes importarlo desde `typing`.
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial013_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ En versiones anteriores a Python 3.9, importa `Annotated` desde `typing_extensions`.
+
+ Ya estará instalado con **FastAPI**.
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial013.py!}
+ ```
+
+Python en sí no hace nada con este `Annotated`. Y para editores y otras herramientas, el tipo sigue siendo "str".
+
+Pero puedes usar este espacio en `Annotated` para proporcionar a **FastAPI** metadatos adicionales sobre cómo quieres que se comporte tu aplicación.
+
+Lo importante que debe recordar es que **el primer *argumento de tipo*** que pasa a `Annotated` es el **tipo real**. El resto son solo metadatos para otras herramientas.
+
+Por ahora, sólo necesitas saber que `Annotated` existe y que es tandard Python. 😎
+
+Más adelante verás lo **poderoso** que puede ser.
+
+!!! tip "Consejo"
+ El hecho de que sea **standard Python** significa que seguirás obteniendo la **mejor experiencia de desarrollador posible** en tu editor, con las herramientas que utilizas para analizar y refactorizar tu código, etc. ✨
+
+ Y también que su código será muy compatible con muchas otras herramientas y bibliotecas de Python. 🚀
+
+## "Type Hints" en **FastAPI**
+
+**FastAPI** aprovecha estos "type hints" para hacer varias cosas.
+
+Con **FastAPI** declaras los parámetros con "type hints" y obtienes:
* **Soporte en el editor**.
-* **Type checks**.
+* **Chequeos de tipo**.
...y **FastAPI** usa las mismas declaraciones para:
-* **Definir requerimientos**: desde request path parameters, query parameters, headers, bodies, dependencies, etc.
-* **Convertir datos**: desde el request al tipo requerido.
-* **Validar datos**: viniendo de cada request:
+* **Definir requerimientos**: desde `request path parameters`, `query parameters`, `headers`, `bodies`, `dependencies`, etc.
+* **Convertir datos**: desde el `request` al tipo requerido.
+* **Validar datos**: viniendo de cada `request`:
* Generando **errores automáticos** devueltos al cliente cuando los datos son inválidos.
* **Documentar** la API usando OpenAPI:
* que en su caso es usada por las interfaces de usuario de la documentación automática e interactiva.
-Puede que todo esto suene abstracto. Pero no te preocupes que todo lo verás en acción en el [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
+Puede que todo esto suene abstracto. Pero no te preocupes que todo lo verás en acción en el [Tutorial - Guía de Usuario](tutorial/index.md){.internal-link target=_blank}.
-Lo importante es que usando los tipos de Python estándar en un único lugar (en vez de añadir más clases, decorator, etc.) **FastAPI** hará mucho del trabajo por ti.
+Lo importante es que usando los tipos estándar de Python en un único lugar (en vez de añadir más clases, decorators, etc.) **FastAPI** hará mucho del trabajo por ti.
!!! info "Información"
Si ya pasaste por todo el tutorial y volviste a la sección de los tipos, una buena referencia es la "cheat sheet" de `mypy`.