|
| 1 | +# Introducción a los Tipos de Python |
| 2 | + |
| 3 | +**Python 3.6+** tiene soporte para <abbr title="en español, anotaciones de tipo. En inglés también se conocen como: type annotations">"type hints"</abbr> opcionales. |
| 4 | + |
| 5 | +Estos **type hints** son una nueva sintáxis, desde Python 3.6+, que permite declarar el <abbr title="por ejemplo: str, int, float, bool">tipo</abbr> de una variable. |
| 6 | + |
| 7 | +Usando las declaraciones de tipos para tus variables, los editores y otras herramientas pueden proveerte un soporte mejor. |
| 8 | + |
| 9 | +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. |
| 10 | + |
| 11 | +Todo **FastAPI** está basado en estos type hints, lo que le da muchas ventajas y beneficios. |
| 12 | + |
| 13 | +Pero, así nunca uses **FastAPI** te beneficiarás de aprender un poco sobre los type hints. |
| 14 | + |
| 15 | +!!! note "Nota" |
| 16 | + Si eres un experto en Python y ya lo sabes todo sobre los type hints, salta al siguiente capítulo. |
| 17 | + |
| 18 | +## Motivación |
| 19 | + |
| 20 | +Comencemos con un ejemplo simple: |
| 21 | + |
| 22 | +```Python |
| 23 | +{!../../../docs_src/python_types/tutorial001.py!} |
| 24 | +``` |
| 25 | + |
| 26 | +Llamar este programa nos muestra el siguiente <abbr title="en español: salida">output</abbr>: |
| 27 | + |
| 28 | +``` |
| 29 | +John Doe |
| 30 | +``` |
| 31 | + |
| 32 | +La función hace lo siguiente: |
| 33 | + |
| 34 | +* Toma un `first_name` y un `last_name`. |
| 35 | +* Convierte la primera letra de cada uno en una letra mayúscula con `title()`. |
| 36 | +* Las <abbr title="las junta como si fuesen una. Con el contenido de una después de la otra. En inlgés: concatenate.">concatena</abbr> con un espacio en la mitad. |
| 37 | + |
| 38 | +```Python hl_lines="2" |
| 39 | +{!../../../docs_src/python_types/tutorial001.py!} |
| 40 | +``` |
| 41 | + |
| 42 | +### Edítalo |
| 43 | + |
| 44 | +Es un programa muy simple. |
| 45 | + |
| 46 | +Ahora, imagina que lo estás escribiendo desde ceros. |
| 47 | + |
| 48 | +En algún punto habrías comenzado con la definición de la función, tenías los parámetros listos... |
| 49 | + |
| 50 | +Pero, luego tienes que llamar "ese método que convierte la primera letra en una mayúscula". |
| 51 | + |
| 52 | +Era `upper`? O era `uppercase`? `first_uppercase`? `capitalize`? |
| 53 | + |
| 54 | +Luego lo intentas con el viejo amigo de los programadores, el autocompletado del editor. |
| 55 | + |
| 56 | +Escribes el primer parámetro de la función `first_name`, luego un punto (`.`) y luego presionas `Ctrl+Space` para iniciar el autocompletado. |
| 57 | + |
| 58 | +Tristemente, no obtienes nada útil: |
| 59 | + |
| 60 | +<img src="https://fastapi.tiangolo.com/img/python-types/image01.png"> |
| 61 | + |
| 62 | +### Añade tipos |
| 63 | + |
| 64 | +Vamos a modificar una única línea de la versión previa. |
| 65 | + |
| 66 | +Vamos a cambiar exactamente este fragmento, los parámetros de la función, de: |
| 67 | + |
| 68 | +```Python |
| 69 | + first_name, last_name |
| 70 | +``` |
| 71 | + |
| 72 | +a: |
| 73 | + |
| 74 | +```Python |
| 75 | + first_name: str, last_name: str |
| 76 | +``` |
| 77 | + |
| 78 | +Eso es todo. |
| 79 | + |
| 80 | +Esos son los "type hints": |
| 81 | + |
| 82 | +```Python hl_lines="1" |
| 83 | +{!../../../docs_src/python_types/tutorial002.py!} |
| 84 | +``` |
| 85 | + |
| 86 | +No es lo mismo a declarar valores por defecto, como sería con: |
| 87 | + |
| 88 | +```Python |
| 89 | + first_name="john", last_name="doe" |
| 90 | +``` |
| 91 | + |
| 92 | +Es algo diferente. |
| 93 | + |
| 94 | +Estamos usando los dos puntos (`:`), no un símbolo de igual (`=`). |
| 95 | + |
| 96 | +Añadir los type hints normalmente no cambia lo que sucedería si ellos no estuviesen presentes. |
| 97 | + |
| 98 | +Pero ahora imagina que nuevamente estás creando la función, pero con los type hints. |
| 99 | + |
| 100 | +En el mismo punto intentas iniciar el autocompletado con `Ctrl+Space` y ves: |
| 101 | + |
| 102 | +<img src="https://fastapi.tiangolo.com/img/python-types/image02.png"> |
| 103 | + |
| 104 | +Con esto puedes moverte hacia abajo viendo las opciones hasta que encuentras una que te suene: |
| 105 | + |
| 106 | +<img src="https://fastapi.tiangolo.com/img/python-types/image03.png"> |
| 107 | + |
| 108 | +## Más motivación |
| 109 | + |
| 110 | +Mira esta función que ya tiene type hints: |
| 111 | + |
| 112 | +```Python hl_lines="1" |
| 113 | +{!../../../docs_src/python_types/tutorial003.py!} |
| 114 | +``` |
| 115 | + |
| 116 | +Como el editor conoce el tipo de las variables no solo obtienes autocompletado, si no que también obtienes chequeo de errores: |
| 117 | + |
| 118 | +<img src="https://fastapi.tiangolo.com/img/python-types/image04.png"> |
| 119 | + |
| 120 | +Ahora que sabes que tienes que arreglarlo convierte `age` a un string con `str(age)`: |
| 121 | + |
| 122 | +```Python hl_lines="2" |
| 123 | +{!../../../docs_src/python_types/tutorial004.py!} |
| 124 | +``` |
| 125 | + |
| 126 | +## Declarando tipos |
| 127 | + |
| 128 | +Acabas de ver el lugar principal para declarar los type hints. Como parámetros de las funciones. |
| 129 | + |
| 130 | +Este es también el lugar principal en que los usarías con **FastAPI**. |
| 131 | + |
| 132 | +### Tipos simples |
| 133 | + |
| 134 | +Puedes declarar todos los tipos estándar de Python, no solamente `str`. |
| 135 | + |
| 136 | +Por ejemplo, puedes usar: |
| 137 | + |
| 138 | +* `int` |
| 139 | +* `float` |
| 140 | +* `bool` |
| 141 | +* `bytes` |
| 142 | + |
| 143 | +```Python hl_lines="1" |
| 144 | +{!../../../docs_src/python_types/tutorial005.py!} |
| 145 | +``` |
| 146 | + |
| 147 | +### Tipos con sub-tipos |
| 148 | + |
| 149 | +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. |
| 150 | + |
| 151 | +Para declarar esos tipos y sub-tipos puedes usar el módulo estándar de Python `typing`. |
| 152 | + |
| 153 | +Él existe específicamente para dar soporte a este tipo de type hints. |
| 154 | + |
| 155 | +#### Listas |
| 156 | + |
| 157 | +Por ejemplo, vamos a definir una variable para que sea una `list` compuesta de `str`. |
| 158 | + |
| 159 | +De `typing`, importa `List` (con una `L` mayúscula): |
| 160 | + |
| 161 | +```Python hl_lines="1" |
| 162 | +{!../../../docs_src/python_types/tutorial006.py!} |
| 163 | +``` |
| 164 | + |
| 165 | +Declara la variable con la misma sintáxis de los dos puntos (`:`). |
| 166 | + |
| 167 | +Pon `List` como el tipo. |
| 168 | + |
| 169 | +Como la lista es un tipo que permite tener un "sub-tipo" pones el sub-tipo en corchetes `[]`: |
| 170 | + |
| 171 | +```Python hl_lines="4" |
| 172 | +{!../../../docs_src/python_types/tutorial006.py!} |
| 173 | +``` |
| 174 | + |
| 175 | +Esto significa: la variable `items` es una `list` y cada uno de los ítems en esta lista es un `str`. |
| 176 | + |
| 177 | +Con esta declaración tu editor puede proveerte soporte inclusive mientras está procesando ítems de la lista. |
| 178 | + |
| 179 | +Sin tipos el autocompletado en este tipo de estructura es casi imposible de lograr: |
| 180 | + |
| 181 | +<img src="https://fastapi.tiangolo.com/img/python-types/image05.png"> |
| 182 | + |
| 183 | +Observa que la variable `item` es unos de los elementos en la lista `items`. |
| 184 | + |
| 185 | +El editor aún sabe que es un `str` y provee soporte para ello. |
| 186 | + |
| 187 | +#### Tuples y Sets |
| 188 | + |
| 189 | +Harías lo mismo para declarar `tuple`s y `set`s: |
| 190 | + |
| 191 | +```Python hl_lines="1 4" |
| 192 | +{!../../../docs_src/python_types/tutorial007.py!} |
| 193 | +``` |
| 194 | + |
| 195 | +Esto significa: |
| 196 | + |
| 197 | +* La variable `items_t` es un `tuple` con 3 ítems, un `int`, otro `int`, y un `str`. |
| 198 | +* La variable `items_s` es un `set` y cada uno de sus ítems es de tipo `bytes`. |
| 199 | + |
| 200 | +#### Diccionarios (Dicts) |
| 201 | + |
| 202 | +Para definir un `dict` le pasas 2 sub-tipos separados por comas. |
| 203 | + |
| 204 | +El primer sub-tipo es para los keys del `dict`. |
| 205 | + |
| 206 | +El segundo sub-tipo es para los valores del `dict`: |
| 207 | + |
| 208 | +```Python hl_lines="1 4" |
| 209 | +{!../../../docs_src/python_types/tutorial008.py!} |
| 210 | +``` |
| 211 | + |
| 212 | +Esto significa: |
| 213 | + |
| 214 | +* La variable `prices` es un `dict`: |
| 215 | + * Los keys de este `dict` son de tipo `str` (Digamos que son el nombre de cada ítem). |
| 216 | + * Los valores de este `dict` son de tipo `float` (Digamos que son el precio de cada ítem). |
| 217 | + |
| 218 | +### Clases como tipos |
| 219 | + |
| 220 | +También puedes declarar una clase como el tipo de una variable. |
| 221 | + |
| 222 | +Digamos que tienes una clase `Person`con un nombre: |
| 223 | + |
| 224 | +```Python hl_lines="1 2 3" |
| 225 | +{!../../../docs_src/python_types/tutorial009.py!} |
| 226 | +``` |
| 227 | + |
| 228 | +Entonces puedes declarar una variable que sea de tipo `Person`: |
| 229 | + |
| 230 | +```Python hl_lines="6" |
| 231 | +{!../../../docs_src/python_types/tutorial009.py!} |
| 232 | +``` |
| 233 | + |
| 234 | +Una vez más tendrás todo el soporte del editor: |
| 235 | + |
| 236 | +<img src="https://fastapi.tiangolo.com/img/python-types/image06.png"> |
| 237 | + |
| 238 | +## Modelos de Pydantic |
| 239 | + |
| 240 | +<a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> es una library de Python para llevar a cabo validación de datos. |
| 241 | + |
| 242 | +Tú declaras la "forma" de los datos mediante clases con atributos. |
| 243 | + |
| 244 | +Cada atributo tiene un tipo. |
| 245 | + |
| 246 | +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. |
| 247 | + |
| 248 | +Y obtienes todo el soporte del editor con el objeto resultante. |
| 249 | + |
| 250 | +Tomado de la documentación oficial de Pydantic: |
| 251 | + |
| 252 | +```Python |
| 253 | +{!../../../docs_src/python_types/tutorial010.py!} |
| 254 | +``` |
| 255 | + |
| 256 | +!!! info "Información" |
| 257 | + Para aprender más sobre <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic mira su documentación</a>. |
| 258 | + |
| 259 | +**FastAPI** está todo basado en Pydantic. |
| 260 | + |
| 261 | +Vas a ver mucho más de esto en práctica en el [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}. |
| 262 | + |
| 263 | +## Type hints en **FastAPI** |
| 264 | + |
| 265 | +**FastAPI** aprovecha estos type hints para hacer varias cosas. |
| 266 | + |
| 267 | +Con **FastAPI** declaras los parámetros con type hints y obtienes: |
| 268 | + |
| 269 | +* **Soporte en el editor**. |
| 270 | +* **Type checks**. |
| 271 | + |
| 272 | +...y **FastAPI** usa las mismas declaraciones para: |
| 273 | + |
| 274 | +* **Definir requerimientos**: desde request path parameters, query parameters, headers, bodies, dependencies, etc. |
| 275 | +* **Convertir datos**: desde el request al tipo requerido. |
| 276 | +* **Validar datos**: viniendo de cada request: |
| 277 | + * Generando **errores automáticos** devueltos al cliente cuando los datos son inválidos. |
| 278 | +* **Documentar** la API usando OpenAPI: |
| 279 | + * que en su caso es usada por las interfaces de usuario de la documentación automática e interactiva. |
| 280 | + |
| 281 | +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}. |
| 282 | + |
| 283 | +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. |
| 284 | + |
| 285 | +!!! info "Información" |
| 286 | + Si ya pasaste por todo el tutorial y volviste a la sección de los tipos, una buena referencia es <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">la "cheat sheet" de `mypy`</a>. |
0 commit comments