<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Pythons · DacaCode &lt;/&gt;</title><link>https://blog.dacadev.com/python/</link><description>Blog de tecnología, programación y electrónica, para compartir conocimientos, experiencias y tutoriales con este apasionante mundo.</description><generator>Hugo</generator><language>es-CO</language><copyright>Copyright © 2026 DacaDev. All rights reserved.</copyright><lastBuildDate>Wed, 24 Jun 2026 00:00:00 -0500</lastBuildDate><atom:link href="https://blog.dacadev.com/python/index.xml" rel="self" type="application/rss+xml"/><image><url>https://blog.dacadev.com/images/blog-logo.png</url><title>DacaCode &lt;/&gt;</title><link>https://blog.dacadev.com/</link></image><item><title>aiohttp: Peticiones HTTP Concurrentes con asyncio</title><link>https://blog.dacadev.com/python/asyncio/aiohttp-peticiones-concurrentes/</link><pubDate>Wed, 24 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/aiohttp-peticiones-concurrentes/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende a hacer peticiones HTTP concurrentes con aiohttp y a coordinarlas con gather, as_completed y wait en asyncio para maximizar el rendimiento.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/aiohttp/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#el-patrón-async-with-context-managers-asíncronos"&gt;El Patrón &lt;code&gt;async with&lt;/code&gt;: Context Managers Asíncronos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#aiohttp-sesiones-y-connection-pooling"&gt;aiohttp: Sesiones y Connection Pooling&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#configurando-timeouts"&gt;Configurando Timeouts&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-trampa-del-await-secuencial"&gt;La Trampa del &lt;code&gt;await&lt;/code&gt; Secuencial&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#gather-recolectar-todos-los-resultados"&gt;&lt;code&gt;gather&lt;/code&gt;: Recolectar Todos los Resultados&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#manejo-de-excepciones-en-gather"&gt;Manejo de Excepciones en &lt;code&gt;gather&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#as_completed-procesar-a-medida-que-terminan"&gt;&lt;code&gt;as_completed&lt;/code&gt;: Procesar a Medida que Terminan&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#wait-control-fino-sobre-la-espera"&gt;&lt;code&gt;wait&lt;/code&gt;: Control Fino sobre la Espera&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cuál-debo-usar"&gt;¿Cuál Debo Usar?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En el &lt;a href="https://blog.dacadev.com/python/asyncio/futures-awaitables-errores-comunes"



 


&gt;artículo anterior&lt;/a&gt; cerramos con una regla clave: nunca uses APIs bloqueantes como &lt;code&gt;requests&lt;/code&gt; dentro de una coroutine, porque bloquean el event loop. La alternativa asíncrona por excelencia para clientes HTTP es &lt;a href="https://docs.aiohttp.org/"




 target="_blank"
 


&gt;&lt;code&gt;aiohttp&lt;/code&gt;&lt;/a&gt;. En este artículo la pondremos en práctica y, más importante aún, veremos cómo coordinar &lt;strong&gt;cientos de peticiones concurrentes&lt;/strong&gt; con las tres APIs que &lt;code&gt;asyncio&lt;/code&gt; ofrece para esto: &lt;code&gt;gather&lt;/code&gt;, &lt;code&gt;as_completed&lt;/code&gt; y &lt;code&gt;wait&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Aprenderás a usar &lt;code&gt;aiohttp&lt;/code&gt; con sesiones y &lt;em&gt;connection pooling&lt;/em&gt;, a entender el patrón &lt;code&gt;async with&lt;/code&gt;, y a elegir entre &lt;code&gt;gather&lt;/code&gt;, &lt;code&gt;as_completed&lt;/code&gt; y &lt;code&gt;wait&lt;/code&gt; según necesites resultados ordenados, procesamiento incremental o control fino sobre la cancelación.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="el-patrón-async-with-context-managers-asíncronos"&gt;El Patrón &lt;code&gt;async with&lt;/code&gt;: Context Managers Asíncronos&lt;/h2&gt;
&lt;p&gt;Antes de tocar &lt;code&gt;aiohttp&lt;/code&gt; debemos entender el patrón sobre el que se construye. Un &lt;strong&gt;context manager síncrono&lt;/strong&gt; se define con &lt;code&gt;__enter__&lt;/code&gt; y &lt;code&gt;__exit__&lt;/code&gt; y nos permite adquirir y liberar recursos de forma segura con &lt;code&gt;with&lt;/code&gt;. Su equivalente asíncrono usa los métodos &lt;code&gt;__aenter__&lt;/code&gt; y &lt;code&gt;__aexit__&lt;/code&gt;, y se consume con &lt;code&gt;async with&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La diferencia es que estos métodos son coroutines: pueden usar &lt;code&gt;await&lt;/code&gt; internamente para adquirir o liberar el recurso sin bloquear el event loop.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;ConnectedSocket&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;server_socket&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_connection&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_server_socket&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;server_socket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__aenter__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;): &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;loop&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get_event_loop&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;connection&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;address&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;loop&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sock_accept&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_server_socket&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_connection&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;connection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_connection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__aexit__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;exc_type&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;exc_val&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;exc_tb&lt;/span&gt;): &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_connection&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;__aenter__&lt;/code&gt; se ejecuta al entrar al bloque &lt;code&gt;async with&lt;/code&gt; y retorna el recurso (la conexión).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__aexit__&lt;/code&gt; se ejecuta al salir del bloque —incluso si hay una excepción— y libera el recurso.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Esto es relevante porque, como veremos enseguida, tanto la sesión de &lt;code&gt;aiohttp&lt;/code&gt; como cada petición que hacemos son context managers asíncronos.&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant C as Código (async with)
 participant CM as Context Manager
 C-&gt;&gt;CM: await __aenter__()
 Note over CM: adquiere el recurso (sin bloquear)
 CM--&gt;&gt;C: retorna el recurso
 Note over C: ejecuta el bloque async with
 C-&gt;&gt;CM: await __aexit__()
 Note over CM: libera el recurso
&lt;/pre&gt;

&lt;h2 id="aiohttp-sesiones-y-connection-pooling"&gt;aiohttp: Sesiones y Connection Pooling&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;aiohttp&lt;/code&gt;, y los clientes HTTP en general, se basan en el concepto de &lt;strong&gt;sesión&lt;/strong&gt;. Una &lt;code&gt;ClientSession&lt;/code&gt; mantiene abiertas varias conexiones que luego se reutilizan entre peticiones. Esto se conoce como &lt;strong&gt;connection pooling&lt;/strong&gt; y es fundamental para el rendimiento: crear una conexión TCP es costoso, así que reutilizar un pool reduce drásticamente esa sobrecarga.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;result&lt;/span&gt;: &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;result&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;() &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;: &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;status&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Status para &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;session.get(url)&lt;/code&gt; es un context manager asíncrono: dentro del bloque tenemos la respuesta; al salir, la conexión vuelve al pool.&lt;/li&gt;
&lt;li&gt;La sesión también se gestiona con &lt;code&gt;async with&lt;/code&gt;, garantizando que todas las conexiones se cierren correctamente al terminar.&lt;/li&gt;
&lt;/ol&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Crea &lt;strong&gt;una sola&lt;/strong&gt; &lt;code&gt;ClientSession&lt;/code&gt; y reutilízala para todas tus peticiones. Crear una sesión por petición desperdicia el &lt;em&gt;connection pooling&lt;/em&gt; y degrada el rendimiento.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="configurando-timeouts"&gt;Configurando Timeouts&lt;/h3&gt;
&lt;p&gt;Por defecto &lt;code&gt;aiohttp&lt;/code&gt; aplica un timeout de &lt;strong&gt;cinco minutos&lt;/strong&gt; a cada operación. Para la mayoría de aplicaciones ese valor es demasiado alto. Podemos ajustarlo con &lt;code&gt;ClientTimeout&lt;/code&gt;, tanto a nivel de sesión (aplica a todas las peticiones) como a nivel de petición individual.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;diez_millis&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientTimeout&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;.01&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# por petición&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;timeout&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e06c75"&gt;diez_millis&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;result&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;result&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;session_timeout&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientTimeout&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;connect&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;.1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# por sesión&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;timeout&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e06c75"&gt;session_timeout&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El parámetro &lt;code&gt;total&lt;/code&gt; limita la duración completa de la operación; &lt;code&gt;connect&lt;/code&gt; limita solo el tiempo de establecer la conexión. El timeout de la petición tiene prioridad sobre el de la sesión.&lt;/p&gt;
&lt;h2 id="la-trampa-del-await-secuencial"&gt;La Trampa del &lt;code&gt;await&lt;/code&gt; Secuencial&lt;/h2&gt;
&lt;p&gt;Antes de lanzar muchas peticiones, hay un error sutil que conviene evitar. Supongamos que queremos ejecutar varias coroutines y recolectar resultados con una &lt;em&gt;list comprehension&lt;/em&gt;:&lt;/p&gt;



&lt;div class="tab" data-tab-group=""&gt;
 &lt;ul class="tab-nav" data-tab-nav&gt;
 
 &lt;li
 class="tab-nav-item active"
 data-tab="secuencial" tabindex="0"&gt;
 ❌ Secuencial
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="concurrente" tabindex="-1"&gt;
 ✅ Concurrente
 &lt;/li&gt;
 
 &lt;/ul&gt;
 &lt;div class="tab-content" data-tab-content&gt;
 
 &lt;div
 class="tab-content-panel active"
 data-tab-panel="secuencial"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;delay_times&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;# await dentro del comprehension → espera cada task antes de crear el siguiente&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;)) &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;delay_times&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tarda &lt;strong&gt;~9 segundos&lt;/strong&gt;. El &lt;code&gt;await&lt;/code&gt; fuerza a esperar cada task antes de crear el siguiente.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="concurrente"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;delay_times&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tasks&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;)) &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;delay_times&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;tasks&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tarda &lt;strong&gt;~3 segundos&lt;/strong&gt;. Primero se crean todos los tasks, luego se esperan.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La clave está en separar la &lt;strong&gt;creación&lt;/strong&gt; de los tasks (que los pone a correr en el event loop) de la &lt;strong&gt;espera&lt;/strong&gt; de sus resultados. Si haces &lt;code&gt;await&lt;/code&gt; mientras los creas, los serializas. Esta separación es precisamente lo que las siguientes APIs resuelven por nosotros.&lt;/p&gt;
&lt;h2 id="gather-recolectar-todos-los-resultados"&gt;&lt;code&gt;gather&lt;/code&gt;: Recolectar Todos los Resultados&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asyncio.gather&lt;/code&gt; recibe una secuencia de awaitables, los ejecuta concurrentemente y, cuando hacemos &lt;code&gt;await&lt;/code&gt; sobre él, espera a que &lt;strong&gt;todos&lt;/strong&gt; terminen y retorna una lista con sus resultados. Si le pasamos coroutines, las envuelve en tasks automáticamente, así que no necesitamos llamar a &lt;code&gt;create_task&lt;/code&gt; manualmente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;() &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;urls&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;_&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;requests&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;urls&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;status_codes&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;gather&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;requests&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;status_codes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;gather&lt;/code&gt; ejecuta las 1000 peticiones de forma concurrente y retorna sus códigos de estado.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Una garantía importante: aunque las peticiones terminen en cualquier orden, &lt;strong&gt;los resultados se devuelven en el mismo orden en que pasamos los awaitables&lt;/strong&gt;. Esto hace que &lt;code&gt;gather&lt;/code&gt; sea ideal cuando necesitas correlacionar cada resultado con su entrada.&lt;/p&gt;
&lt;h3 id="manejo-de-excepciones-en-gather"&gt;Manejo de Excepciones en &lt;code&gt;gather&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;El comportamiento ante errores se controla con el parámetro &lt;code&gt;return_exceptions&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;return_exceptions=False&lt;/code&gt;&lt;/strong&gt; (por defecto): si cualquier awaitable lanza una excepción, esa excepción se propaga al hacer &lt;code&gt;await gather&lt;/code&gt;. El resto de coroutines &lt;strong&gt;siguen ejecutándose&lt;/strong&gt;, pero perdemos sus resultados a menos que manejemos la excepción.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;return_exceptions=True&lt;/code&gt;&lt;/strong&gt;: las excepciones se devuelven como parte de la lista de resultados, junto a los valores exitosos. &lt;code&gt;gather&lt;/code&gt; nunca lanza, y nosotros decidimos cómo tratar cada error.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;results&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;gather&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;requests&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;return_exceptions&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;exitos&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;results&lt;/span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;not&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;r&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Exception&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;errores&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;results&lt;/span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;r&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Exception&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;gather&lt;/code&gt; tiene dos limitaciones: no es fácil &lt;strong&gt;cancelar&lt;/strong&gt; las peticiones restantes cuando una falla, y debemos esperar a que &lt;strong&gt;todas&lt;/strong&gt; terminen antes de procesar cualquier resultado. Si una petición tarda 20 s y otra 100 ms, nos bloqueamos 20 s antes de poder usar la rápida.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="as_completed-procesar-a-medida-que-terminan"&gt;&lt;code&gt;as_completed&lt;/code&gt;: Procesar a Medida que Terminan&lt;/h2&gt;
&lt;p&gt;Cuando queremos reaccionar a cada resultado &lt;strong&gt;en cuanto está disponible&lt;/strong&gt;, &lt;code&gt;asyncio.as_completed&lt;/code&gt; es la herramienta. Recibe una lista de awaitables y retorna un iterador de futures. Al iterar y hacer &lt;code&gt;await&lt;/code&gt; sobre cada uno, obtenemos los resultados en el orden en que van &lt;strong&gt;completándose&lt;/strong&gt;, no en el que los pasamos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;() &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;finished_task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;as_completed&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;finished_task&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# se imprime apenas cada uno termina&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Las dos primeras peticiones se imprimen alrededor del segundo 1, sin esperar a la de 10 segundos. Esto mejora la &lt;strong&gt;responsividad&lt;/strong&gt; de la aplicación. También nos da mejor control de errores: la excepción de un task se lanza justo cuando hacemos &lt;code&gt;await&lt;/code&gt; sobre él, permitiéndonos manejarla en el momento.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;as_completed&lt;/code&gt; admite un &lt;code&gt;timeout&lt;/code&gt; global. Si se excede, el &lt;code&gt;await&lt;/code&gt; sobre los futures pendientes lanza &lt;code&gt;asyncio.TimeoutError&lt;/code&gt;, que podemos capturar:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;done_task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;as_completed&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;timeout&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;done_task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;except&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;TimeoutError&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;¡Timeout!&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre class="mermaid"&gt;flowchart LR
 subgraph gather["gather → espera TODO"]
 G1[req 1s] --&gt; GW[⏳ bloquea hasta el más lento]
 G2[req 1s] --&gt; GW
 G3[req 10s] --&gt; GW
 GW --&gt; GR[procesa los 3 resultados]
 end
 subgraph asc["as_completed → procesa al terminar"]
 A1[req 1s] --&gt; AR1[procesa ~1s]
 A2[req 1s] --&gt; AR2[procesa ~1s]
 A3[req 10s] --&gt; AR3[procesa ~10s]
 end
&lt;/pre&gt;

&lt;p&gt;La desventaja de &lt;code&gt;as_completed&lt;/code&gt; es que no es fácil saber &lt;strong&gt;qué&lt;/strong&gt; tasks ya terminaron y cuáles siguen pendientes: los recibimos uno a uno por el iterador.&lt;/p&gt;
&lt;h2 id="wait-control-fino-sobre-la-espera"&gt;&lt;code&gt;wait&lt;/code&gt;: Control Fino sobre la Espera&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asyncio.wait&lt;/code&gt; es la opción más flexible. Recibe una colección de tasks y retorna &lt;strong&gt;dos conjuntos&lt;/strong&gt;: &lt;code&gt;done&lt;/code&gt; (los que terminaron, con resultado o excepción) y &lt;code&gt;pending&lt;/code&gt; (los que siguen corriendo). A diferencia de las otras APIs, &lt;code&gt;wait&lt;/code&gt; &lt;strong&gt;no lanza excepciones&lt;/strong&gt; automáticamente ni cancela tasks por timeout; nos da el control y la responsabilidad.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Es buena práctica envolver las coroutines en &lt;code&gt;create_task&lt;/code&gt; antes de pasarlas a &lt;code&gt;wait&lt;/code&gt;. En versiones recientes de Python, &lt;code&gt;wait&lt;/code&gt; espera objetos &lt;code&gt;Task&lt;/code&gt;, no coroutines crudas.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Su comportamiento se ajusta con el parámetro &lt;code&gt;return_when&lt;/code&gt;, que acepta tres valores:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;code&gt;return_when&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;wait&lt;/code&gt; retorna cuando…&lt;/th&gt;
 &lt;th&gt;Uso típico&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ALL_COMPLETED&lt;/code&gt; (def.)&lt;/td&gt;
 &lt;td&gt;todos los tasks terminan&lt;/td&gt;
 &lt;td&gt;equivalente a &lt;code&gt;gather&lt;/code&gt;, pero con &lt;code&gt;done&lt;/code&gt;/&lt;code&gt;pending&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FIRST_EXCEPTION&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;el primero falla (o todos terminan si no hay errores)&lt;/td&gt;
 &lt;td&gt;cancelar el resto al primer error&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FIRST_COMPLETED&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;el primero termina (con éxito o error)&lt;/td&gt;
 &lt;td&gt;reaccionar al más rápido y cancelar el resto&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Como &lt;code&gt;wait&lt;/code&gt; nos entrega el conjunto &lt;code&gt;pending&lt;/code&gt;, podemos cancelar explícitamente los tasks que ya no necesitamos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;() &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;done&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;pending&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;wait&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;return_when&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;FIRST_COMPLETED&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Terminados: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;len&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; | Pendientes: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;len&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;pending&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;done&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;exception&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;is&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;: &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;task&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;result&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Error: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;task&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;exception&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;pending&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;cancel&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Como los tasks en &lt;code&gt;done&lt;/code&gt; ya terminaron, es seguro consultar &lt;code&gt;exception()&lt;/code&gt; y &lt;code&gt;result()&lt;/code&gt;. Esto evita usar &lt;code&gt;await&lt;/code&gt; con &lt;code&gt;try/except&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Cancelamos manualmente lo que quedó pendiente —algo que &lt;code&gt;gather&lt;/code&gt; no permite hacer con facilidad.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sobre los &lt;strong&gt;timeouts&lt;/strong&gt; en &lt;code&gt;wait&lt;/code&gt;: si pasas el parámetro &lt;code&gt;timeout&lt;/code&gt; y se agota, &lt;code&gt;wait&lt;/code&gt; simplemente retorna &lt;code&gt;done&lt;/code&gt; y &lt;code&gt;pending&lt;/code&gt; hasta ese momento, &lt;strong&gt;sin lanzar excepción&lt;/strong&gt; y &lt;strong&gt;sin cancelar&lt;/strong&gt; los tasks pendientes. Tú decides qué hacer con ellos.&lt;/p&gt;
&lt;h2 id="cuál-debo-usar"&gt;¿Cuál Debo Usar?&lt;/h2&gt;
&lt;p&gt;Las tres APIs ejecutan awaitables concurrentemente; la elección depende de cómo necesites consumir los resultados.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 Start{¿Cómo necesito&lt;br/&gt;los resultados?} --&gt; A[Todos juntos&lt;br/&gt;y ordenados]
 Start --&gt; B[Cada uno apenas&lt;br/&gt;termina]
 Start --&gt; C[Control fino:&lt;br/&gt;done/pending,&lt;br/&gt;cancelar el resto]

 A --&gt; AG["asyncio.gather"]
 B --&gt; AC["asyncio.as_completed"]
 C --&gt; AW["asyncio.wait"]

 style AG fill:#3b82f6,stroke:#1e40af,color:#fff
 style AC fill:#f59e0b,stroke:#b45309,color:#fff
 style AW fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;gather&lt;/code&gt;&lt;/strong&gt; → la opción más simple cuando quieres &lt;strong&gt;todos los resultados, en orden&lt;/strong&gt;, y un único punto donde manejar el éxito o el error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;as_completed&lt;/code&gt;&lt;/strong&gt; → cuando quieres &lt;strong&gt;procesar cada resultado en cuanto llega&lt;/strong&gt; y mejorar la responsividad.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;wait&lt;/code&gt;&lt;/strong&gt; → cuando necesitas &lt;strong&gt;control fino&lt;/strong&gt;: saber qué terminó y qué sigue pendiente, manejar errores sin excepciones implícitas y cancelar tasks manualmente.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aiohttp&lt;/code&gt; es el reemplazo asíncrono de &lt;code&gt;requests&lt;/code&gt;; usa una &lt;code&gt;ClientSession&lt;/code&gt; con &lt;strong&gt;connection pooling&lt;/strong&gt; y reutilízala entre peticiones.&lt;/li&gt;
&lt;li&gt;Tanto la sesión como cada petición son &lt;strong&gt;context managers asíncronos&lt;/strong&gt; (&lt;code&gt;async with&lt;/code&gt;), construidos sobre &lt;code&gt;__aenter__&lt;/code&gt;/&lt;code&gt;__aexit__&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Separa la &lt;strong&gt;creación&lt;/strong&gt; de tasks de su &lt;strong&gt;espera&lt;/strong&gt;: hacer &lt;code&gt;await&lt;/code&gt; mientras los creas los serializa.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gather&lt;/code&gt; espera todo y devuelve resultados &lt;strong&gt;ordenados&lt;/strong&gt;; controla errores con &lt;code&gt;return_exceptions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;as_completed&lt;/code&gt; entrega resultados &lt;strong&gt;a medida que terminan&lt;/strong&gt;, ideal para responsividad.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wait&lt;/code&gt; ofrece &lt;strong&gt;control fino&lt;/strong&gt; con los conjuntos &lt;code&gt;done&lt;/code&gt;/&lt;code&gt;pending&lt;/code&gt; y los modos &lt;code&gt;ALL_COMPLETED&lt;/code&gt;, &lt;code&gt;FIRST_EXCEPTION&lt;/code&gt; y &lt;code&gt;FIRST_COMPLETED&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aiohttp.org/"




 target="_blank"
 


&gt;aiohttp — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.gather"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.gather&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.as_completed&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.wait"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.wait&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-0492/"




 target="_blank"
 


&gt;PEP 492 — Coroutines with async and await syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Matthew Fowler, &lt;em&gt;Python Concurrency with asyncio&lt;/em&gt; (Manning, 2022)&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Futures, Awaitables y Errores Comunes en asyncio</title><link>https://blog.dacadev.com/python/asyncio/futures-awaitables-errores-comunes/</link><pubDate>Wed, 13 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/futures-awaitables-errores-comunes/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Entiende qué son los futures y awaitables en asyncio, cómo medir el rendimiento de código asíncrono y los errores más comunes que bloquean el event loop en Python.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/futures-awaitables/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#futures-un-valor-que-aún-no-existe"&gt;Futures: Un Valor que Aún No Existe&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#futures-en-la-práctica"&gt;Futures en la práctica&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-jerarquía-de-los-awaitables"&gt;La Jerarquía de los Awaitables&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#midiendo-el-tiempo-de-ejecución"&gt;Midiendo el Tiempo de Ejecución&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#uso-en-la-práctica"&gt;Uso en la práctica&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#errores-comunes-en-asyncio"&gt;Errores Comunes en &lt;code&gt;asyncio&lt;/code&gt;&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#1-ejecutar-código-cpu-bound-en-coroutines"&gt;1. Ejecutar código CPU-bound en coroutines&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#2-usar-apis-bloqueantes"&gt;2. Usar APIs bloqueantes&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En los artículos anteriores aprendimos a crear &lt;a href="https://blog.dacadev.com/python/asyncio/coroutines-async-await"



 


&gt;coroutines con async/await&lt;/a&gt; y ejecutar tasks concurrentes. En este artículo vamos a cerrar el modelo mental: entenderemos qué son los &lt;strong&gt;futures&lt;/strong&gt;, cómo se relacionan con tasks y coroutines a través de los &lt;strong&gt;awaitables&lt;/strong&gt;, y veremos cómo medir el rendimiento de nuestro código asíncrono. Para cerrar, hablaremos de los dos errores más comunes al trabajar con &lt;code&gt;asyncio&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="futures-un-valor-que-aún-no-existe"&gt;Futures: Un Valor que Aún No Existe&lt;/h2&gt;
&lt;p&gt;Un &lt;strong&gt;future&lt;/strong&gt; es un objeto de Python que representa un valor que esperamos obtener en algún momento, pero que &lt;strong&gt;todavía no tenemos&lt;/strong&gt;. Cuando se crea, un future está en estado &lt;em&gt;incompleto&lt;/em&gt;. Una vez que el valor llega, se establece con &lt;code&gt;set_result&lt;/code&gt; y el future pasa a estar &lt;em&gt;completado&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¿Está completo? &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;set_result&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;42&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¿Está completo? &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Resultado: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;result&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre class="mermaid"&gt;stateDiagram-v2
 [*] --&gt; Incompleto: Future()
 Incompleto --&gt; Completado: set_result(valor)
 Completado --&gt; [*]: result() → valor

 note right of Incompleto
 done() → False
 result() → InvalidStateError
 end note

 note right of Completado
 done() → True
 result() → valor
 end note
&lt;/pre&gt;

&lt;h3 id="futures-en-la-práctica"&gt;Futures en la práctica&lt;/h3&gt;
&lt;p&gt;En la mayoría de los casos no crearás futures directamente — &lt;code&gt;asyncio&lt;/code&gt; los gestiona internamente. Pero entender su mecánica es clave para comprender cómo funciona todo por dentro. Veamos un ejemplo donde un task establece el valor de un future después de un segundo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;hacer_peticion&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;establecer_valor&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;future&lt;/span&gt;)) &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;establecer_valor&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;future&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;set_result&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;42&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;hacer_peticion&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¿Está completo? &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¿Está completo? &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Crea un task que configurará el valor del future.&lt;/li&gt;
&lt;li&gt;Espera 1 segundo antes de establecer el resultado.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;await&lt;/code&gt; pausa &lt;code&gt;main()&lt;/code&gt; hasta que el future reciba su valor.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant M as main()
 participant F as Future
 participant T as task: establecer_valor()

 M-&gt;&gt;F: hacer_peticion() → Future incompleto
 M-&gt;&gt;T: create_task(establecer_valor(future))
 M-&gt;&gt;F: await future
 Note over M: ⏸ PAUSE main()
 T-&gt;&gt;T: await asyncio.sleep(1)
 Note over T: ⏳ 1 segundo...
 T-&gt;&gt;F: set_result(42)
 Note over F: ✅ Completado
 F--&gt;&gt;M: ▶ RESUME main()
 Note over M: valor = 42
&lt;/pre&gt;

&lt;h2 id="la-jerarquía-de-los-awaitables"&gt;La Jerarquía de los Awaitables&lt;/h2&gt;
&lt;p&gt;Tanto las coroutines como los tasks pueden usarse con &lt;code&gt;await&lt;/code&gt;. ¿Qué tienen en común? Ambos son &lt;strong&gt;awaitables&lt;/strong&gt; — objetos que implementan el método &lt;code&gt;__await__&lt;/code&gt;, que es lo que Python necesita para poder usar la palabra clave &lt;code&gt;await&lt;/code&gt; sobre ellos.&lt;/p&gt;
&lt;p&gt;La relación entre estos conceptos forma una jerarquía clara:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A["Awaitable\n(__await__)"] --&gt; B["Coroutine"]
 A --&gt; C["Future"]
 C --&gt; D["Task"]

 style A fill:#8b5cf6,stroke:#5b21b6,color:#fff
 style B fill:#3b82f6,stroke:#1e40af,color:#fff
 style C fill:#f59e0b,stroke:#b45309,color:#fff
 style D fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Awaitable&lt;/strong&gt; es la clase base que define el protocolo &lt;code&gt;__await__&lt;/code&gt;. Todo lo que se pueda usar con &lt;code&gt;await&lt;/code&gt; es un awaitable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coroutine&lt;/strong&gt; es una función definida con &lt;code&gt;async def&lt;/code&gt;. Hereda de &lt;code&gt;Awaitable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future&lt;/strong&gt; representa un valor pendiente. También hereda de &lt;code&gt;Awaitable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task&lt;/strong&gt; hereda de &lt;code&gt;Future&lt;/code&gt;. Es la combinación de un future y una coroutine: encapsula una coroutine y la ejecuta en el event loop, mientras que el future subyacente almacena el resultado cuando la coroutine termina.&lt;/li&gt;
&lt;/ul&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Un &lt;strong&gt;Future&lt;/strong&gt; es &lt;em&gt;qué&lt;/em&gt; esperamos obtener. Un &lt;strong&gt;Task&lt;/strong&gt; es &lt;em&gt;cómo&lt;/em&gt; lo obtenemos (ejecutando una coroutine). Y &lt;strong&gt;Awaitable&lt;/strong&gt; es el contrato que ambos cumplen para que &lt;code&gt;await&lt;/code&gt; funcione.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="midiendo-el-tiempo-de-ejecución"&gt;Midiendo el Tiempo de Ejecución&lt;/h2&gt;
&lt;p&gt;Cuando trabajamos con código asíncrono, medir cuánto tarda cada operación es esencial para verificar que la concurrencia realmente funciona. La mejor forma de hacerlo es con un &lt;strong&gt;decorador&lt;/strong&gt; que registre el tiempo de inicio y fin de cada coroutine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;functools&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;async_timed&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;wrapper&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;func&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#61afef"&gt;@functools.wraps&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;wrapped&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;args&lt;/span&gt;, &lt;span style="color:#56b6c2"&gt;**&lt;/span&gt;&lt;span style="color:#e06c75"&gt;kwargs&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Any&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;starting &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;func&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; with args &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;args&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;kwargs&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;time&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;func&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;args&lt;/span&gt;, &lt;span style="color:#56b6c2"&gt;**&lt;/span&gt;&lt;span style="color:#e06c75"&gt;kwargs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;finally&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;end&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;time&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;end&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;-&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;finished &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;func&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; in &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;&lt;span style="color:#98c379"&gt;:&lt;/span&gt;&lt;span style="color:#98c379"&gt;.4f&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; second(s)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;wrapped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;wrapper&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="uso-en-la-práctica"&gt;Uso en la práctica&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef"&gt;@async_timed&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;delay&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;sleeping for &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; second(s)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;finished sleeping for &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; second(s)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef"&gt;@async_timed&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;task_one&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;task_two&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task_one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task_two&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;starting &amp;lt;function main ...&amp;gt; with args () {}
starting &amp;lt;function delay ...&amp;gt; with args (2,) {}
starting &amp;lt;function delay ...&amp;gt; with args (3,) {}
finished &amp;lt;function delay ...&amp;gt; in 2.0032 second(s)
finished &amp;lt;function delay ...&amp;gt; in 3.0003 second(s)
finished &amp;lt;function main ...&amp;gt; in 3.0004 second(s)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;El output confirma lo que esperamos: ambos tasks corren concurrentemente. &lt;code&gt;delay(2)&lt;/code&gt; termina a los ~2 segundos, &lt;code&gt;delay(3)&lt;/code&gt; a los ~3, y &lt;code&gt;main()&lt;/code&gt; tarda ~3 segundos en total (no 5).&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Ejecución concurrente verificada con @async_timed
 dateFormat X
 axisFormat %s

 section delay(2)
 sleep(2) :a1, 0, 2

 section delay(3)
 sleep(3) :b1, 0, 3

 section main()
 Tiempo total :c1, 0, 3
&lt;/pre&gt;

&lt;h2 id="errores-comunes-en-asyncio"&gt;Errores Comunes en &lt;code&gt;asyncio&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Hay dos trampas frecuentes que pueden arruinar el rendimiento de una aplicación async. Ambas tienen la misma causa: &lt;strong&gt;bloquear el event loop&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="1-ejecutar-código-cpu-bound-en-coroutines"&gt;1. Ejecutar código CPU-bound en coroutines&lt;/h3&gt;
&lt;p&gt;Cuando tenemos funciones computacionalmente costosas (cálculos matemáticos, procesamiento de datos grandes), puede parecer buena idea envolverlas en tasks para ejecutarlas concurrentemente. Pero recuerda: &lt;code&gt;asyncio&lt;/code&gt; usa &lt;strong&gt;un solo hilo&lt;/strong&gt;. El GIL garantiza que solo una instrucción de bytecode se ejecute a la vez, así que el código CPU-bound bloqueará el event loop sin importar cuántos tasks crees.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A["Código CPU-bound\nen una coroutine"] --&gt;|"Bloquea el\nevent loop 🛑"| B["Otras tareas\nno pueden ejecutarse"]
 C["Solución"] --&gt; D["multiprocessing\no run_in_executor()"]

 style A fill:#ef4444,stroke:#991b1b,color:#fff
 style B fill:#ef4444,stroke:#991b1b,color:#fff
 style D fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;h3 id="2-usar-apis-bloqueantes"&gt;2. Usar APIs bloqueantes&lt;/h3&gt;
&lt;p&gt;El mismo problema ocurre al usar librerías de I/O que no son asíncronas. Librerías como &lt;code&gt;requests&lt;/code&gt; o funciones como &lt;code&gt;time.sleep&lt;/code&gt; bloquean el hilo principal. Cuando las llamas dentro de una coroutine, &lt;strong&gt;bloqueas el event loop completo&lt;/strong&gt; y ninguna otra coroutine puede ejecutarse.&lt;/p&gt;



&lt;div class="tab" data-tab-group=""&gt;
 &lt;ul class="tab-nav" data-tab-nav&gt;
 
 &lt;li
 class="tab-nav-item active"
 data-tab="bloqueante" tabindex="0"&gt;
 ❌ Bloqueante
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="no-bloqueante" tabindex="-1"&gt;
 ✅ No bloqueante
 &lt;/li&gt;
 
 &lt;/ul&gt;
 &lt;div class="tab-content" data-tab-content&gt;
 
 &lt;div
 class="tab-content-panel active"
 data-tab-panel="bloqueante"&gt;
 &lt;h4 id="no-uses-estas-funciones-dentro-de-coroutines"&gt;No uses estas funciones dentro de coroutines&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;requests.get()&lt;/code&gt; → bloquea el event loop&lt;/li&gt;
&lt;li&gt;&lt;code&gt;time.sleep()&lt;/code&gt; → bloquea el event loop&lt;/li&gt;
&lt;li&gt;Cualquier función de I/O síncrona&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="no-bloqueante"&gt;
 &lt;h4 id="usa-las-alternativas-asíncronas"&gt;Usa las alternativas asíncronas&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aiohttp.org/"




 target="_blank"
 


&gt;&lt;code&gt;aiohttp&lt;/code&gt;&lt;/a&gt; → reemplazo async de &lt;code&gt;requests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asyncio.sleep()&lt;/code&gt; → cede control al event loop&lt;/li&gt;
&lt;li&gt;&lt;a href="https://magicstack.github.io/asyncpg/"




 target="_blank"
 


&gt;&lt;code&gt;asyncpg&lt;/code&gt;&lt;/a&gt; → cliente async de PostgreSQL&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Tinche/aiofiles"




 target="_blank"
 


&gt;&lt;code&gt;aiofiles&lt;/code&gt;&lt;/a&gt; → lectura/escritura async de archivos&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
 
 &lt;/div&gt;
&lt;/div&gt;





 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;strong&gt;Regla general:&lt;/strong&gt; cualquier función que realice I/O y no sea una coroutine, o que ejecute operaciones CPU costosas, debe considerarse bloqueante. Para CPU-bound, usa &lt;a href="https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor"




 target="_blank"
 


&gt;&lt;code&gt;loop.run_in_executor()&lt;/code&gt;&lt;/a&gt; con un &lt;code&gt;ProcessPoolExecutor&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Un &lt;strong&gt;Future&lt;/strong&gt; representa un valor que aún no existe — se completa con &lt;code&gt;set_result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;Task&lt;/strong&gt; es un future + una coroutine: ejecuta la coroutine y almacena su resultado en el future subyacente.&lt;/li&gt;
&lt;li&gt;Todo lo que se pueda usar con &lt;code&gt;await&lt;/code&gt; es un &lt;strong&gt;Awaitable&lt;/strong&gt; — el contrato que unifica coroutines, futures y tasks.&lt;/li&gt;
&lt;li&gt;El decorador &lt;code&gt;@async_timed&lt;/code&gt; permite verificar que la concurrencia funciona midiendo tiempos reales.&lt;/li&gt;
&lt;li&gt;Los dos errores más comunes son ejecutar &lt;strong&gt;código CPU-bound&lt;/strong&gt; y usar &lt;strong&gt;APIs bloqueantes&lt;/strong&gt; dentro de coroutines — ambos bloquean el event loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-future.html"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.Future&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.Task"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.Task&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/reference/datamodel.html#awaitable-objects"




 target="_blank"
 


&gt;Python Data Model — Awaitables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/async-io-python/"




 target="_blank"
 


&gt;Real Python — Async IO in Python: A Complete Walkthrough&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-3156/"




 target="_blank"
 


&gt;PEP 3156 — Asynchronous IO Support Rebooted&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Coroutines y async/await: Tu Primer Código Asíncrono en Python</title><link>https://blog.dacadev.com/python/asyncio/coroutines-async-await/</link><pubDate>Tue, 12 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/coroutines-async-await/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende a crear coroutines con async def, pausar la ejecución con await, usar asyncio.run y evitar la trampa del await secuencial en Python.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/coroutines-async-await/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-es-una-coroutine"&gt;¿Qué es una Coroutine?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#creando-coroutines"&gt;Creando Coroutines&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#ejecutando-coroutines-con-asynciorun"&gt;Ejecutando Coroutines con &lt;code&gt;asyncio.run&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#pausando-la-ejecución-con-await"&gt;Pausando la Ejecución con &lt;code&gt;await&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#simulando-operaciones-largas-con-asynciosleep"&gt;Simulando Operaciones Largas con &lt;code&gt;asyncio.sleep&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-trampa-del-await-secuencial"&gt;La Trampa del &lt;code&gt;await&lt;/code&gt; Secuencial&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#el-problema-visualizado"&gt;El problema visualizado&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cómo-logramos-concurrencia-real"&gt;¿Cómo logramos concurrencia real?&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En los artículos anteriores construimos la base teórica: &lt;a href="https://blog.dacadev.com/python/asyncio/fundamentos-asyncio"



 


&gt;concurrencia vs paralelismo&lt;/a&gt;, &lt;a href="https://blog.dacadev.com/python/asyncio/procesos-hilos-event-loop"



 


&gt;procesos, hilos, el GIL y el event loop&lt;/a&gt;. Ahora es momento de escribir código. En este artículo vamos a aprender a crear &lt;strong&gt;coroutines&lt;/strong&gt;, usar las palabras clave &lt;code&gt;async&lt;/code&gt; y &lt;code&gt;await&lt;/code&gt;, y entender exactamente qué pasa cuando pausamos y reanudamos la ejecución.&lt;/p&gt;
&lt;h2 id="qué-es-una-coroutine"&gt;¿Qué es una Coroutine?&lt;/h2&gt;
&lt;p&gt;Una coroutine es como una función normal de Python, pero con un superpoder: &lt;strong&gt;puede pausar su ejecución&lt;/strong&gt; cuando encuentra una operación que podría tardar (una petición de red, una lectura de disco, una espera). Mientras la coroutine está pausada, el event loop puede ejecutar otras tareas. Cuando la operación termina, la coroutine se &amp;ldquo;despierta&amp;rdquo; y continúa desde donde se detuvo.&lt;/p&gt;
&lt;p&gt;Esta capacidad de pausar y reanudar es lo que le da concurrencia a nuestra aplicación.&lt;/p&gt;
&lt;p&gt;Para trabajar con coroutines necesitamos dos palabras clave:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;async def&lt;/code&gt;&lt;/strong&gt; → define una coroutine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;await&lt;/code&gt;&lt;/strong&gt; → pausa la coroutine hasta que la operación esperada termine.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="creando-coroutines"&gt;Creando Coroutines&lt;/h2&gt;
&lt;p&gt;Crear una coroutine es casi idéntico a crear una función normal. La única diferencia es usar &lt;code&gt;async def&lt;/code&gt; en lugar de &lt;code&gt;def&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;mi_coroutine&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;¡Hola mundo!&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;strong&gt;Llamar a una coroutine no la ejecuta.&lt;/strong&gt; Solo produce un objeto coroutine. Para ejecutarla, necesitas un event loop.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# ❌ Esto NO ejecuta la coroutine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;mi_coroutine&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# Retorna un objeto coroutine, no imprime nada&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# ✅ Esto SÍ la ejecuta&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mi_coroutine&lt;/span&gt;()) &lt;span style="color:#7f848e"&gt;# Imprime: ¡Hola mundo!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ejecutando-coroutines-con-asynciorun"&gt;Ejecutando Coroutines con &lt;code&gt;asyncio.run&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asyncio.run&lt;/code&gt; es el &lt;strong&gt;punto de entrada principal&lt;/strong&gt; de cualquier aplicación asyncio. Veamos un ejemplo concreto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numero&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;resultado&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;resultado&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;asyncio.run&lt;/code&gt; hace varias cosas por nosotros:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Crea&lt;/strong&gt; un event loop nuevo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ejecuta&lt;/strong&gt; la coroutine que le pasamos hasta que se completa.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retorna&lt;/strong&gt; el resultado de la coroutine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limpia&lt;/strong&gt; cualquier tarea pendiente y cierra el event loop.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A["asyncio.run(coroutine)"] --&gt; B["Crea el\nEvent Loop"]
 B --&gt; C["Ejecuta la\ncoroutine"]
 C --&gt; D["Retorna\nel resultado"]
 D --&gt; E["Cierra el\nEvent Loop"]

 style A fill:#3b82f6,stroke:#1e40af,color:#fff
 style C fill:#10b981,stroke:#065f46,color:#fff
 style E fill:#64748b,stroke:#334155,color:#fff
&lt;/pre&gt;





 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;asyncio.run&lt;/code&gt; está diseñado para ejecutarse &lt;strong&gt;una sola vez&lt;/strong&gt; como entrada principal de tu aplicación. Esa única coroutine debería encargarse de lanzar todas las demás tareas.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="pausando-la-ejecución-con-await"&gt;Pausando la Ejecución con &lt;code&gt;await&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;El verdadero poder de asyncio está en &lt;code&gt;await&lt;/code&gt;. Esta palabra clave hace dos cosas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Ejecuta&lt;/strong&gt; la coroutine que le sigue (a diferencia de llamarla directamente, que solo crea el objeto).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pausa&lt;/strong&gt; la coroutine contenedora hasta que la coroutine esperada retorne un resultado.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cuando la coroutine esperada termina, la coroutine contenedora se &amp;ldquo;despierta&amp;rdquo; y puede usar el resultado.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;obtener_saludo&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;¡Hola desde una coroutine!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;saludo&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obtener_saludo&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# Pausa main() hasta obtener el resultado&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;saludo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="simulando-operaciones-largas-con-asynciosleep"&gt;Simulando Operaciones Largas con &lt;code&gt;asyncio.sleep&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Para simular una operación de I/O de larga duración (como una petición HTTP o una consulta a base de datos), podemos usar &lt;code&gt;asyncio.sleep&lt;/code&gt;. Esta función pausa la coroutine por el número de segundos indicado, cediendo el control al event loop.&lt;/p&gt;
&lt;p&gt;Veamos un ejemplo más completo con una función auxiliar &lt;code&gt;delay&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;delay&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Esperando &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; segundo(s)...&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¡Espera de &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; segundo(s) completada!&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Esperé &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; segundo(s)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="la-trampa-del-await-secuencial"&gt;La Trampa del &lt;code&gt;await&lt;/code&gt; Secuencial&lt;/h2&gt;
&lt;p&gt;Ahora veamos un error muy común al empezar con asyncio. Considera este código:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numero&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;mensaje_hola_mundo&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;¡Hola Mundo!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mensaje&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;mensaje_hola_mundo&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# Pausa 1 segundo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;uno_mas_uno&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# Ejecuta después de la pausa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;uno_mas_uno&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mensaje&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cuando ejecutamos este código, &lt;strong&gt;pasa 1 segundo&lt;/strong&gt; antes de que se impriman ambos resultados. Pero &lt;code&gt;sumar_uno(1)&lt;/code&gt; es instantánea — ¿por qué espera?&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;await&lt;/code&gt; pausa toda la coroutine contenedora.&lt;/strong&gt; No se ejecuta ningún otro código dentro de &lt;code&gt;main()&lt;/code&gt; hasta que la expresión &lt;code&gt;await&lt;/code&gt; retorne un valor. Como &lt;code&gt;mensaje_hola_mundo()&lt;/code&gt; tarda 1 segundo, &lt;code&gt;main()&lt;/code&gt; queda pausada ese segundo completo antes de siquiera llegar a &lt;code&gt;sumar_uno(1)&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El siguiente diagrama muestra exactamente qué pasa en cada momento:&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant EL as Event Loop
 participant M as main()
 participant HW as mensaje_hola_mundo()
 participant AO as sumar_uno(1)

 EL-&gt;&gt;M: ▶ RUN main()
 Note over M: await mensaje_hola_mundo()
 M-&gt;&gt;HW: ▶ RUN mensaje_hola_mundo()
 HW-&gt;&gt;HW: await sleep(1)
 Note over M: ⏸ PAUSE main()
 Note over HW: ⏸ PAUSE mensaje_hola_mundo()
 Note over EL: ⏳ Pasa 1 segundo...
 EL-&gt;&gt;HW: ▶ RESUME mensaje_hola_mundo()
 Note over HW: return '¡Hola Mundo!'
 HW--&gt;&gt;M: ▶ RESUME main()
 Note over M: mensaje = '¡Hola Mundo!'
 Note over M: await sumar_uno(1)
 M-&gt;&gt;AO: ▶ RUN sumar_uno(1)
 Note over AO: return 1 + 1
 AO--&gt;&gt;M: ▶ RESUME main()
 Note over M: uno_mas_uno = 2
 Note over M: print() resultados
&lt;/pre&gt;

&lt;h3 id="el-problema-visualizado"&gt;El problema visualizado&lt;/h3&gt;
&lt;p&gt;El flujo de ejecución es completamente &lt;strong&gt;secuencial&lt;/strong&gt;, a pesar de usar &lt;code&gt;async/await&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Ejecución secuencial — Sin concurrencia real
 dateFormat X
 axisFormat %s

 section main()
 await mensaje_hola_mundo() :a1, 0, 10
 await sumar_uno(1) :a2, 10, 11
 print() resultados :a3, 11, 12
&lt;/pre&gt;

&lt;p&gt;Lo que &lt;em&gt;queremos&lt;/em&gt; es que &lt;code&gt;sumar_uno(1)&lt;/code&gt; se ejecute &lt;strong&gt;mientras&lt;/strong&gt; &lt;code&gt;mensaje_hola_mundo()&lt;/code&gt; espera su segundo de delay. Pero con &lt;code&gt;await&lt;/code&gt; secuencial eso no es posible — cada &lt;code&gt;await&lt;/code&gt; bloquea la coroutine hasta completarse.&lt;/p&gt;
&lt;h3 id="cómo-logramos-concurrencia-real"&gt;¿Cómo logramos concurrencia real?&lt;/h3&gt;
&lt;p&gt;Para ejecutar múltiples coroutines de forma concurrente necesitamos herramientas como &lt;code&gt;asyncio.gather&lt;/code&gt; o &lt;code&gt;asyncio.create_task&lt;/code&gt;. Un adelanto rápido:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;# ✅ Ambas coroutines corren concurrentemente&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mensaje&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;uno_mas_uno&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;gather&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mensaje_hola_mundo&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;uno_mas_uno&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mensaje&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Con &lt;code&gt;gather&lt;/code&gt;, el event loop puede ejecutar &lt;code&gt;sumar_uno(1)&lt;/code&gt; mientras &lt;code&gt;mensaje_hola_mundo()&lt;/code&gt; está pausada esperando su &lt;code&gt;sleep&lt;/code&gt;. El tiempo total se mantiene en ~1 segundo en lugar de sumar ambos tiempos.&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Ejecución concurrente — Con asyncio.gather
 dateFormat X
 axisFormat %s

 section mensaje_hola_mundo()
 await sleep(1) :a1, 0, 10

 section sumar_uno(1)
 return 1 + 1 :a2, 0, 1

 section main()
 print() resultados :a3, 10, 11
&lt;/pre&gt;

&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A["async def"] --&gt;|"Define"| B["Coroutine"]
 B --&gt;|"Se ejecuta con"| C["asyncio.run()"]
 B --&gt;|"Se pausa con"| D["await"]
 D --&gt;|"Cede control al"| E["Event Loop"]
 E --&gt;|"Cuando I/O completa"| F["Reanuda la coroutine"]
 C --&gt;|"Crea y gestiona"| E

 style A fill:#8b5cf6,stroke:#5b21b6,color:#fff
 style B fill:#3b82f6,stroke:#1e40af,color:#fff
 style D fill:#f59e0b,stroke:#b45309,color:#fff
 style E fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;async def&lt;/code&gt;&lt;/strong&gt; define una coroutine — una función que puede pausarse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;await&lt;/code&gt;&lt;/strong&gt; pausa la coroutine actual hasta que la operación esperada termine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;asyncio.run&lt;/code&gt;&lt;/strong&gt; crea el event loop y ejecuta la coroutine principal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;asyncio.sleep&lt;/code&gt;&lt;/strong&gt; simula operaciones de I/O de larga duración.&lt;/li&gt;
&lt;li&gt;Usar &lt;code&gt;await&lt;/code&gt; de forma secuencial &lt;strong&gt;no da concurrencia&lt;/strong&gt; — para eso necesitamos &lt;code&gt;asyncio.gather&lt;/code&gt; o &lt;code&gt;asyncio.create_task&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio&lt;/code&gt; — Documentación Oficial: Coroutines and Tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-0492/"




 target="_blank"
 


&gt;PEP 492 — Coroutines with async and await syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/async-io-python/"




 target="_blank"
 


&gt;Real Python — Async IO in Python: A Complete Walkthrough&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>asyncio: Cómo Funcionan los Procesos, Hilos y el Event Loop</title><link>https://blog.dacadev.com/python/asyncio/procesos-hilos-event-loop/</link><pubDate>Mon, 11 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/procesos-hilos-event-loop/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Entiende qué son los procesos e hilos en Python, cómo el GIL afecta la concurrencia, y cómo asyncio logra concurrencia con un solo hilo gracias al event loop.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/processes-threads/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#procesos-e-hilos"&gt;Procesos e Hilos&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-es-un-proceso"&gt;¿Qué es un proceso?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#qué-es-un-hilo-thread"&gt;¿Qué es un hilo (thread)?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#verificándolo-en-python"&gt;Verificándolo en Python&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#el-global-interpreter-lock-gil"&gt;El Global Interpreter Lock (GIL)&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#el-gil-se-libera-alguna-vez"&gt;¿El GIL se libera alguna vez?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#asyncio-y-el-gil"&gt;&lt;code&gt;asyncio&lt;/code&gt; y el GIL&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#concurrencia-de-un-solo-hilo"&gt;Concurrencia de Un Solo Hilo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cómo-funciona-el-event-loop"&gt;Cómo Funciona el Event Loop&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En el &lt;a href="https://blog.dacadev.com/python/asyncio/fundamentos-asyncio"



 


&gt;artículo anterior&lt;/a&gt; construimos un modelo mental sobre concurrencia, paralelismo y los tipos de multitarea. Ahora vamos a bajar un nivel: entender qué son los procesos y los hilos, por qué el GIL de Python cambia las reglas del juego, y cómo &lt;code&gt;asyncio&lt;/code&gt; logra concurrencia con un solo hilo gracias al event loop.&lt;/p&gt;
&lt;h2 id="procesos-e-hilos"&gt;Procesos e Hilos&lt;/h2&gt;
&lt;h3 id="qué-es-un-proceso"&gt;¿Qué es un proceso?&lt;/h3&gt;
&lt;p&gt;Un &lt;strong&gt;proceso&lt;/strong&gt; es una instancia de una aplicación en ejecución. Cada proceso tiene su propio espacio de memoria aislado — ningún otro proceso puede acceder a él directamente — y se ejecuta en un CPU o núcleo del sistema.&lt;/p&gt;
&lt;h3 id="qué-es-un-hilo-thread"&gt;¿Qué es un hilo (thread)?&lt;/h3&gt;
&lt;p&gt;Un &lt;strong&gt;hilo&lt;/strong&gt; es una unidad de ejecución más ligera que vive &lt;em&gt;dentro&lt;/em&gt; de un proceso. A diferencia de los procesos, los hilos no tienen su propia memoria: comparten el espacio de memoria del proceso que los creó.&lt;/p&gt;
&lt;p&gt;Todo proceso tiene al menos un hilo asociado, conocido como el &lt;strong&gt;hilo principal&lt;/strong&gt; (&lt;em&gt;main thread&lt;/em&gt;). Además, un proceso puede crear hilos adicionales, comúnmente llamados &lt;strong&gt;hilos de trabajo&lt;/strong&gt; (&lt;em&gt;worker threads&lt;/em&gt;) o &lt;strong&gt;hilos en segundo plano&lt;/strong&gt; (&lt;em&gt;background threads&lt;/em&gt;).&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
 subgraph P1["Proceso (PID: 1234)"]
 direction TB
 M1["Memoria del proceso"]
 MT["Hilo principal\n(main thread)"]
 W1["Worker thread 1"]
 W2["Worker thread 2"]
 M1 &lt;--&gt; MT
 M1 &lt;--&gt; W1
 M1 &lt;--&gt; W2
 end

 style P1 fill:transparent,stroke:#64748b
 style M1 fill:#3b82f6,stroke:#1e40af,color:#fff
 style MT fill:#10b981,stroke:#065f46,color:#fff
 style W1 fill:#f59e0b,stroke:#b45309,color:#fff
 style W2 fill:#f59e0b,stroke:#b45309,color:#fff
&lt;/pre&gt;





 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Todos los hilos dentro de un proceso comparten la misma memoria. Esto hace la comunicación entre hilos muy rápida, pero introduce el riesgo de &lt;strong&gt;condiciones de carrera&lt;/strong&gt; si no se maneja con cuidado.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="verificándolo-en-python"&gt;Verificándolo en Python&lt;/h3&gt;
&lt;p&gt;Puedes inspeccionar el proceso e hilo actual con los módulos &lt;code&gt;os&lt;/code&gt; y &lt;code&gt;threading&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;threading&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Proceso de Python con PID: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;os&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;getpid&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;total_threads&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;threading&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;active_count&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;thread_name&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;threading&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;current_thread&lt;/span&gt;()&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Python está ejecutando &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;total_threads&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; hilo(s)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;El hilo actual es: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;thread_name&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# Output esperado&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Proceso de Python con PID: &lt;span style="color:#d19a66"&gt;48672&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Python está ejecutando &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; hilo&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;s&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;El hilo actual es: MainThread
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Por defecto, tu programa Python corre en un solo hilo (&lt;em&gt;MainThread&lt;/em&gt;) dentro de un solo proceso.&lt;/p&gt;
&lt;h2 id="el-global-interpreter-lock-gil"&gt;El Global Interpreter Lock (GIL)&lt;/h2&gt;
&lt;p&gt;El &lt;strong&gt;GIL&lt;/strong&gt; (&lt;em&gt;Global Interpreter Lock&lt;/em&gt;) es uno de los temas más debatidos en la comunidad Python. En términos simples: el GIL impide que un proceso de Python ejecute más de una instrucción de bytecode a la vez, incluso si tienes múltiples hilos.&lt;/p&gt;
&lt;p&gt;Esto significa que aunque crees varios hilos con &lt;code&gt;threading&lt;/code&gt;, &lt;strong&gt;solo uno ejecuta código Python en cualquier instante&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant GIL
 participant T1 as Hilo 1
 participant T2 as Hilo 2

 GIL-&gt;&gt;T1: 🔓 GIL adquirido
 activate T1
 T1-&gt;&gt;T1: Ejecuta bytecode
 T1-&gt;&gt;GIL: 🔒 Libera GIL
 deactivate T1
 GIL-&gt;&gt;T2: 🔓 GIL adquirido
 activate T2
 T2-&gt;&gt;T2: Ejecuta bytecode
 T2-&gt;&gt;GIL: 🔒 Libera GIL
 deactivate T2
 GIL-&gt;&gt;T1: 🔓 GIL adquirido
 activate T1
 T1-&gt;&gt;T1: Ejecuta bytecode
 deactivate T1
&lt;/pre&gt;

&lt;h3 id="el-gil-se-libera-alguna-vez"&gt;¿El GIL se libera alguna vez?&lt;/h3&gt;
&lt;p&gt;Sí. El GIL &lt;strong&gt;se libera durante las operaciones de I/O&lt;/strong&gt;. Cuando un hilo hace una petición de red o una lectura de disco, libera el GIL, permitiendo que otro hilo tome el control y ejecute código Python mientras tanto.&lt;/p&gt;
&lt;p&gt;Esto es lo que hace que &lt;code&gt;threading&lt;/code&gt; sea útil para trabajo I/O-bound, pero ineficaz para trabajo CPU-bound.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A["Operación\nCPU-bound"] --&gt;|"GIL retenido 🔒"| B["Solo 1 hilo\nejecuta a la vez"]
 C["Operación\nI/O-bound"] --&gt;|"GIL liberado 🔓"| D["Otros hilos pueden\nejecutar código"]

 style A fill:#ef4444,stroke:#991b1b,color:#fff
 style B fill:#ef4444,stroke:#991b1b,color:#fff
 style C fill:#10b981,stroke:#065f46,color:#fff
 style D fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;h3 id="asyncio-y-el-gil"&gt;&lt;code&gt;asyncio&lt;/code&gt; y el GIL&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt; aprovecha exactamente este comportamiento: como las operaciones de I/O liberan el GIL, puede lograr concurrencia &lt;strong&gt;con un solo hilo&lt;/strong&gt;. En lugar de crear múltiples hilos, &lt;code&gt;asyncio&lt;/code&gt; crea objetos llamados &lt;strong&gt;coroutines&lt;/strong&gt; — que puedes pensar como hilos ultra-ligeros.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Mientras una coroutine espera por una operación de I/O, el event loop ejecuta otras coroutines que estén listas. El resultado: concurrencia sin los problemas de sincronización del multithreading.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="concurrencia-de-un-solo-hilo"&gt;Concurrencia de Un Solo Hilo&lt;/h2&gt;
&lt;p&gt;La concurrencia de un solo hilo no se basa en hacer dos cosas simultáneamente (eso sería paralelismo), sino en &lt;strong&gt;aprovechar los tiempos de espera&lt;/strong&gt; de las operaciones de I/O para ejecutar otras tareas. El mecanismo se apoya en tres pilares:&lt;/p&gt;



&lt;div class="tab" data-tab-group=""&gt;
 &lt;ul class="tab-nav" data-tab-nav&gt;
 
 &lt;li
 class="tab-nav-item active"
 data-tab="sockets-no-bloqueantes" tabindex="0"&gt;
 Sockets no bloqueantes
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="delegaci%C3%B3n-al-so" tabindex="-1"&gt;
 Delegación al SO
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="event-loop" tabindex="-1"&gt;
 Event Loop
 &lt;/li&gt;
 
 &lt;/ul&gt;
 &lt;div class="tab-content" data-tab-content&gt;
 
 &lt;div
 class="tab-content-panel active"
 data-tab-panel="sockets-no-bloqueantes"&gt;
 &lt;h4 id="1-sockets-no-bloqueantes"&gt;1. Sockets no bloqueantes&lt;/h4&gt;
&lt;p&gt;A diferencia de un socket estándar que detiene el programa hasta recibir una respuesta, un &lt;strong&gt;socket no bloqueante&lt;/strong&gt; permite enviar una petición y devolver el control al programa inmediatamente, sin esperar el resultado.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="delegaci%C3%B3n-al-so"&gt;
 &lt;h4 id="2-delegación-al-sistema-operativo"&gt;2. Delegación al sistema operativo&lt;/h4&gt;
&lt;p&gt;Cuando el código llega a una operación de red o lectura de disco, Python le delega la espera al sistema operativo. El hilo de ejecución queda libre de inmediato.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="event-loop"&gt;
 &lt;h4 id="3-el-event-loop-como-coordinador"&gt;3. El Event Loop como coordinador&lt;/h4&gt;
&lt;p&gt;Mientras el SO vigila los sockets, el hilo de Python sigue ejecutando otras tareas. Cuando el SO detecta que los datos llegaron, envía una notificación. El event loop recibe este aviso y &amp;ldquo;despierta&amp;rdquo; la tarea pausada para que procese la respuesta.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El siguiente diagrama de secuencia muestra cómo interactúan estos tres pilares:&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant MT as Main Thread
 participant EL as Event Loop
 participant OS as Sistema Operativo
 participant S1 as Socket 1
 participant S2 as Socket 2

 MT-&gt;&gt;EL: Envía tareas
 EL-&gt;&gt;EL: Ejecuta tarea 1 hasta I/O
 EL-&gt;&gt;OS: Registra Socket 1 para monitoreo
 OS-&gt;&gt;S1: Vigila socket
 EL-&gt;&gt;EL: Ejecuta tarea 2 hasta I/O
 EL-&gt;&gt;OS: Registra Socket 2 para monitoreo
 OS-&gt;&gt;S2: Vigila socket
 S1--&gt;&gt;OS: Datos listos ✅
 OS--&gt;&gt;EL: Notifica Socket 1
 EL-&gt;&gt;EL: Reanuda tarea 1
 S2--&gt;&gt;OS: Datos listos ✅
 OS--&gt;&gt;EL: Notifica Socket 2
 EL-&gt;&gt;EL: Reanuda tarea 2
&lt;/pre&gt;

&lt;h2 id="cómo-funciona-el-event-loop"&gt;Cómo Funciona el Event Loop&lt;/h2&gt;
&lt;p&gt;En su forma más básica, un event loop es simplemente un &lt;strong&gt;bucle infinito que procesa mensajes de una cola&lt;/strong&gt;, uno a la vez:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;deque&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;messages&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;deque&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;while&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#e06c75"&gt;messages&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;message&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;messages&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;pop&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;process_message&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En &lt;code&gt;asyncio&lt;/code&gt;, el event loop mantiene una cola de &lt;strong&gt;tasks&lt;/strong&gt; (tareas) en lugar de mensajes simples. Cada task es un wrapper alrededor de una coroutine. Cuando una coroutine alcanza una operación de I/O, se pausa y le devuelve el control al event loop, que puede ejecutar otras tareas que no estén esperando I/O.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A["Event Loop inicia"] --&gt; B["¿Hay tareas en la cola?"]
 B --&gt;|Sí| C["Tomar siguiente tarea"]
 C --&gt; D{"¿La tarea tiene\nI/O pendiente?"}
 D --&gt;|No| E["Ejecutar hasta\nel próximo await"]
 E --&gt; F{"¿La tarea alcanzó\nuna operación I/O?"}
 F --&gt;|Sí| G["Pausar tarea y registrar\nsocket en el SO"]
 F --&gt;|No| H["Tarea completada ✅\nRemover de la cola"]
 G --&gt; B
 H --&gt; B
 D --&gt;|Sí, datos listos| I["Reanudar tarea"]
 I --&gt; F
 D --&gt;|Sí, esperando aún| B
 B --&gt;|No| J["Esperar notificaciones\ndel SO"]
 J --&gt; B

 style A fill:#3b82f6,stroke:#1e40af,color:#fff
 style H fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este ciclo se repite indefinidamente hasta que todas las tareas se completan o el programa se cierra explícitamente. Si una coroutine ejecuta trabajo CPU-bound sin ceder control con &lt;code&gt;await&lt;/code&gt;, &lt;strong&gt;bloqueará todo el event loop&lt;/strong&gt; y ninguna otra tarea podrá avanzar.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Un &lt;strong&gt;proceso&lt;/strong&gt; tiene memoria aislada; un &lt;strong&gt;hilo&lt;/strong&gt; comparte memoria dentro de su proceso.&lt;/li&gt;
&lt;li&gt;El &lt;strong&gt;GIL&lt;/strong&gt; impide paralelismo real con hilos en Python, pero se libera durante operaciones de I/O.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asyncio&lt;/code&gt; aprovecha esta liberación del GIL para lograr &lt;strong&gt;concurrencia en un solo hilo&lt;/strong&gt; mediante coroutines.&lt;/li&gt;
&lt;li&gt;El &lt;strong&gt;event loop&lt;/strong&gt; coordina las tareas: ejecuta coroutines hasta que alcanzan un &lt;code&gt;await&lt;/code&gt;, las pausa, y reanuda otras que ya tengan datos listos.&lt;/li&gt;
&lt;li&gt;Los &lt;strong&gt;sockets no bloqueantes&lt;/strong&gt; y la &lt;strong&gt;delegación al SO&lt;/strong&gt; son los mecanismos que permiten esta concurrencia sin crear múltiples hilos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio.html"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/threading.html"




 target="_blank"
 


&gt;Python &lt;code&gt;threading&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/multiprocessing.html"




 target="_blank"
 


&gt;Python &lt;code&gt;multiprocessing&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/python-gil/"




 target="_blank"
 


&gt;Real Python — What Is the Python Global Interpreter Lock (GIL)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-0703/"




 target="_blank"
 


&gt;PEP 703 — Making the Global Interpreter Lock Optional&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>asyncio: Los Fundamentos de la Programación Asíncrona en Python</title><link>https://blog.dacadev.com/python/asyncio/fundamentos-asyncio/</link><pubDate>Sun, 10 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/fundamentos-asyncio/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende los fundamentos de asyncio en Python: diferencia entre concurrencia y paralelismo, operaciones CPU-bound vs I/O-bound, y cómo funciona la multitarea cooperativa.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/fundamentals/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-es-la-programación-asíncrona"&gt;¿Qué es la programación asíncrona?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cpu-bound-vs-io-bound"&gt;CPU-bound vs. I/O-bound&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#operaciones-limitadas-por-es-io-bound"&gt;Operaciones limitadas por E/S (I/O-bound)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#operaciones-limitadas-por-cpu-cpu-bound"&gt;Operaciones limitadas por CPU (CPU-bound)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#ejemplo-práctico"&gt;Ejemplo práctico&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#concurrencia-vs-paralelismo"&gt;Concurrencia vs. Paralelismo&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#concurrencia-alternar-entre-tareas"&gt;Concurrencia: alternar entre tareas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#paralelismo-ejecución-simultánea-real"&gt;Paralelismo: ejecución simultánea real&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#tipos-de-multitarea"&gt;Tipos de Multitarea&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#multitarea-preventiva-preemptive"&gt;Multitarea preventiva (Preemptive)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#multitarea-cooperativa-cooperative"&gt;Multitarea cooperativa (Cooperative)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#comparación-rápida"&gt;Comparación rápida&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#dónde-encaja-asyncio"&gt;¿Dónde encaja &lt;code&gt;asyncio&lt;/code&gt;?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Si alguna vez construiste un scraper que recorre decenas de páginas, un microservicio que atiende cientos de peticiones o un bot que consume múltiples APIs, seguro sentiste la frustración de esperar. Una petición termina, la siguiente arranca, y tu programa queda ahí sin hacer nada útil.&lt;/p&gt;
&lt;p&gt;La librería &lt;code&gt;asyncio&lt;/code&gt; de Python fue diseñada para resolver exactamente este problema. En este artículo vamos a construir un modelo mental sólido sobre los conceptos clave: concurrencia, paralelismo, multitarea y la diferencia entre operaciones limitadas por CPU y por E/S.&lt;/p&gt;
&lt;h2 id="qué-es-la-programación-asíncrona"&gt;¿Qué es la programación asíncrona?&lt;/h2&gt;
&lt;p&gt;La &lt;strong&gt;programación asíncrona&lt;/strong&gt; es un modelo donde las tareas de larga duración se ejecutan en segundo plano, separadas del flujo principal de tu aplicación. En lugar de bloquear todo mientras esperas una respuesta de red o una lectura de archivo, el sistema queda libre para hacer otro trabajo. Cuando la tarea termina, tu código recibe una notificación y puede procesar el resultado.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt; — abreviación de &lt;strong&gt;asynchronous I/O&lt;/strong&gt; — es la librería estándar de Python que implementa este modelo. Fue introducida en &lt;a href="https://docs.python.org/3/library/asyncio.html"




 target="_blank"
 


&gt;Python 3.4&lt;/a&gt; y hoy es la base de frameworks modernos como &lt;a href="https://fastapi.tiangolo.com/"




 target="_blank"
 


&gt;FastAPI&lt;/a&gt;, &lt;a href="https://docs.aiohttp.org/"




 target="_blank"
 


&gt;aiohttp&lt;/a&gt; y &lt;a href="https://www.starlette.io/"




 target="_blank"
 


&gt;Starlette&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cpu-bound-vs-io-bound"&gt;CPU-bound vs. I/O-bound&lt;/h2&gt;
&lt;p&gt;Antes de avanzar, necesitas entender una distinción fundamental: &lt;strong&gt;¿en qué está gastando tiempo tu código?&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="operaciones-limitadas-por-es-io-bound"&gt;Operaciones limitadas por E/S (I/O-bound)&lt;/h3&gt;
&lt;p&gt;Tu programa pasa la mayor parte del tiempo &lt;strong&gt;esperando un sistema externo&lt;/strong&gt;: la red, el disco, una base de datos. La CPU está prácticamente ociosa. Ejemplos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hacer peticiones HTTP.&lt;/li&gt;
&lt;li&gt;Leer o escribir archivos en disco.&lt;/li&gt;
&lt;li&gt;Consultar una base de datos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="operaciones-limitadas-por-cpu-cpu-bound"&gt;Operaciones limitadas por CPU (CPU-bound)&lt;/h3&gt;
&lt;p&gt;El &lt;strong&gt;procesador&lt;/strong&gt; es el cuello de botella. La CPU está activamente calculando, sin esperas externas. Ejemplos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calcular dígitos de pi.&lt;/li&gt;
&lt;li&gt;Aplicar lógica de negocio sobre estructuras de datos grandes.&lt;/li&gt;
&lt;li&gt;Procesamiento de imágenes o entrenamiento de modelos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ejemplo-práctico"&gt;Ejemplo práctico&lt;/h3&gt;
&lt;p&gt;Considera este fragmento de código:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;requests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;response&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;requests&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;https://www.example.com&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 1 - I/O-bound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;items&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;items&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;headers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;key&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;header&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;key&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;header&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;items&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# 2 - CPU-bound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;formatted_headers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#98c379"&gt;\n&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;join&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 3 - CPU-bound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;open&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;headers.txt&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;file&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;file&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;write&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;formatted_headers&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 4 - I/O-bound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El siguiente diagrama muestra el flujo de ejecución y clasifica cada paso:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A["1. requests.get()"] --&gt;|respuesta| B["2. List comprehension"]
 B --&gt; C["3. join() headers"]
 C --&gt; D["4. file.write()"]

 style A fill:#3b82f6,stroke:#1e40af,color:#fff
 style B fill:#f59e0b,stroke:#b45309,color:#fff
 style C fill:#f59e0b,stroke:#b45309,color:#fff
 style D fill:#3b82f6,stroke:#1e40af,color:#fff
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;🔵 &lt;strong&gt;Azul = I/O-bound&lt;/strong&gt; (esperando red o disco) · 🟡 &lt;strong&gt;Amarillo = CPU-bound&lt;/strong&gt; (procesando en memoria)&lt;/p&gt;
&lt;/blockquote&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt; brilla con cargas &lt;strong&gt;I/O-bound&lt;/strong&gt;. Si tu cuello de botella es la CPU, necesitarás &lt;code&gt;multiprocessing&lt;/code&gt; o &lt;a href="https://docs.python.org/3/library/concurrent.futures.html"




 target="_blank"
 


&gt;concurrent.futures&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="concurrencia-vs-paralelismo"&gt;Concurrencia vs. Paralelismo&lt;/h2&gt;
&lt;p&gt;Estos dos términos se confunden constantemente, pero describen cosas distintas.&lt;/p&gt;
&lt;h3 id="concurrencia-alternar-entre-tareas"&gt;Concurrencia: alternar entre tareas&lt;/h3&gt;
&lt;p&gt;Concurrencia significa &lt;strong&gt;gestionar múltiples tareas en períodos de tiempo superpuestos&lt;/strong&gt;, sin necesidad de ejecutarlas en el mismo instante. Piensa en un chef preparando dos platos: pica verduras para el plato A, lo mete al horno y empieza a trabajar en el plato B mientras el A se cocina. Solo hace una cosa a la vez, pero ambos platos avanzan.&lt;/p&gt;
&lt;p&gt;En un sistema concurrente, una sola CPU alterna entre tareas. Mientras la tarea #1 espera por E/S, la CPU toma la tarea #2.&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Concurrencia — Una sola CPU alternando entre tareas
 dateFormat X
 axisFormat %s

 section CPU
 App #1 :a1, 0, 2
 App #2 :a2, 2, 4
 App #1 :a3, 4, 6
 App #2 :a4, 6, 8
 App #1 :a5, 8, 10
&lt;/pre&gt;

&lt;h3 id="paralelismo-ejecución-simultánea-real"&gt;Paralelismo: ejecución simultánea real&lt;/h3&gt;
&lt;p&gt;Paralelismo significa &lt;strong&gt;ejecutar múltiples tareas al mismo tiempo&lt;/strong&gt;, lo cual requiere múltiples CPUs o núcleos.&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Paralelismo — Múltiples CPUs ejecutando simultáneamente
 dateFormat X
 axisFormat %s

 section CPU 1
 App #1 :a1, 0, 10

 section CPU 2
 App #2 :b1, 0, 10
&lt;/pre&gt;

&lt;p&gt;En palabras de Rob Pike (co-creador de Go): &lt;em&gt;&amp;ldquo;La concurrencia se trata de lidiar con muchas cosas a la vez. El paralelismo se trata de hacer muchas cosas a la vez.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;La concurrencia es un &lt;strong&gt;patrón de diseño&lt;/strong&gt;; el paralelismo es un &lt;strong&gt;modelo de ejecución&lt;/strong&gt;. &lt;code&gt;asyncio&lt;/code&gt; logra concurrencia en un solo hilo, sin paralelismo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="tipos-de-multitarea"&gt;Tipos de Multitarea&lt;/h2&gt;
&lt;p&gt;Existen dos enfoques principales para la multitarea, y entender la diferencia es clave para comprender dónde encaja &lt;code&gt;asyncio&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="multitarea-preventiva-preemptive"&gt;Multitarea preventiva (Preemptive)&lt;/h3&gt;
&lt;p&gt;El &lt;strong&gt;sistema operativo&lt;/strong&gt; decide cuándo cambiar entre tareas mediante un mecanismo llamado &lt;strong&gt;time slicing&lt;/strong&gt;: divide el tiempo de CPU en intervalos pequeños y rota entre las tareas activas. Cuando el SO fuerza un cambio, se dice que está haciendo &lt;em&gt;preemption&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;En Python, este es el modelo que usan los módulos &lt;code&gt;threading&lt;/code&gt; (hilos) y &lt;code&gt;multiprocessing&lt;/code&gt; (procesos). La ventaja es que no tienes que pensar en cuándo ceder el control. La desventaja: los cambios pueden ocurrir en cualquier momento, lo que introduce &lt;strong&gt;condiciones de carrera&lt;/strong&gt; y la necesidad de &lt;strong&gt;locks&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="multitarea-cooperativa-cooperative"&gt;Multitarea cooperativa (Cooperative)&lt;/h3&gt;
&lt;p&gt;Las &lt;strong&gt;propias tareas&lt;/strong&gt; deciden cuándo ceder el control. Cada tarea señala explícitamente: &lt;em&gt;&amp;ldquo;Me pauso aquí, ejecuta otras tareas.&amp;rdquo;&lt;/em&gt; No hay intervención del SO.&lt;/p&gt;
&lt;p&gt;Este es exactamente el modelo de &lt;code&gt;asyncio&lt;/code&gt;. En Python, la palabra clave &lt;code&gt;await&lt;/code&gt; es esa señal explícita:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;obtener_datos&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Obteniendo datos...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 👈 &amp;#34;Me pauso aquí, ejecuta otras tareas&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Datos obtenidos!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;procesar_datos&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Procesando datos...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 👈 Misma señal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Datos procesados!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;gather&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;obtener_datos&lt;/span&gt;(), &lt;span style="color:#e06c75"&gt;procesar_datos&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La ventaja es la &lt;strong&gt;predictibilidad&lt;/strong&gt;: tú controlas exactamente dónde ocurren los cambios. El riesgo: si una tarea olvida hacer &lt;code&gt;await&lt;/code&gt; o ejecuta una operación CPU-bound larga sin ceder control, bloquea todo el event loop.&lt;/p&gt;
&lt;p&gt;El siguiente diagrama de secuencia ilustra cómo el event loop coordina las tareas cooperativamente:&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant EL as Event Loop
 participant T1 as obtener_datos()
 participant T2 as procesar_datos()

 EL-&gt;&gt;T1: Ejecutar
 T1-&gt;&gt;EL: await sleep(2) — cede control
 EL-&gt;&gt;T2: Ejecutar
 T2-&gt;&gt;EL: await sleep(1) — cede control
 EL-&gt;&gt;T2: sleep completado — reanudar
 T2-&gt;&gt;EL: Finalizada ✅
 EL-&gt;&gt;T1: sleep completado — reanudar
 T1-&gt;&gt;EL: Finalizada ✅
&lt;/pre&gt;

&lt;h3 id="comparación-rápida"&gt;Comparación rápida&lt;/h3&gt;



&lt;div class="tab" data-tab-group=""&gt;
 &lt;ul class="tab-nav" data-tab-nav&gt;
 
 &lt;li
 class="tab-nav-item active"
 data-tab="preventiva" tabindex="0"&gt;
 Preventiva
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="cooperativa" tabindex="-1"&gt;
 Cooperativa
 &lt;/li&gt;
 
 &lt;/ul&gt;
 &lt;div class="tab-content" data-tab-content&gt;
 
 &lt;div
 class="tab-content-panel active"
 data-tab-panel="preventiva"&gt;
 &lt;h4 id="multitarea-preventiva"&gt;Multitarea Preventiva&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;¿Quién cambia?&lt;/strong&gt; El Sistema Operativo&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mecanismo:&lt;/strong&gt; Time slicing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Herramientas en Python:&lt;/strong&gt; &lt;code&gt;threading&lt;/code&gt;, &lt;code&gt;multiprocessing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Riesgo principal:&lt;/strong&gt; Condiciones de carrera&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ideal para:&lt;/strong&gt; Cargas CPU-bound o mixtas&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="cooperativa"&gt;
 &lt;h4 id="multitarea-cooperativa"&gt;Multitarea Cooperativa&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;¿Quién cambia?&lt;/strong&gt; La propia tarea&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mecanismo:&lt;/strong&gt; &lt;code&gt;await&lt;/code&gt; / yield&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Herramientas en Python:&lt;/strong&gt; &lt;code&gt;asyncio&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Riesgo principal:&lt;/strong&gt; Bloquear el event loop&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ideal para:&lt;/strong&gt; Cargas I/O-bound&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
 
 &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="dónde-encaja-asyncio"&gt;¿Dónde encaja &lt;code&gt;asyncio&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;Con todos estos conceptos claros, el siguiente diagrama te ayuda a decidir qué herramienta usar según tu caso:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A["¿Qué tipo de operación\nnecesitas optimizar?"] --&gt; B{"¿Es I/O-bound?"}
 B --&gt;|Sí| C{"¿Necesitas manejar\nmuchas conexiones?"}
 C --&gt;|Sí| D["✅ asyncio"]
 C --&gt;|No| E["threading o\nasyncio"]
 B --&gt;|No| F{"¿Es CPU-bound?"}
 F --&gt;|Sí| G{"¿Necesitas compartir\nmemoria entre tareas?"}
 G --&gt;|Sí| H["threading\n+ locks"]
 G --&gt;|No| I["multiprocessing"]
 F --&gt;|Mixto| J["asyncio +\nrun_in_executor()"]

 style D fill:#10b981,stroke:#065f46,color:#fff
 style E fill:#10b981,stroke:#065f46,color:#fff
 style H fill:#f59e0b,stroke:#b45309,color:#fff
 style I fill:#3b82f6,stroke:#1e40af,color:#fff
 style J fill:#8b5cf6,stroke:#5b21b6,color:#fff
&lt;/pre&gt;

&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;asyncio&lt;/code&gt; ofrece &lt;strong&gt;concurrencia&lt;/strong&gt;, no paralelismo — todo corre en un solo hilo.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;multitarea cooperativa&lt;/strong&gt; — tu código cede control explícitamente con &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Destaca en cargas &lt;strong&gt;I/O-bound&lt;/strong&gt; — peticiones de red, operaciones de archivo, consultas a bases de datos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No es la solución&lt;/strong&gt; para trabajo CPU-bound — para eso, combínalo con &lt;code&gt;multiprocessing&lt;/code&gt; o usa &lt;a href="https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor"




 target="_blank"
 


&gt;loop.run_in_executor()&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio.html"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/concurrent.futures.html"




 target="_blank"
 


&gt;Python &lt;code&gt;concurrent.futures&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/async-io-python/"




 target="_blank"
 


&gt;Real Python — Async IO in Python: A Complete Walkthrough&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-3156/"




 target="_blank"
 


&gt;PEP 3156 — Asynchronous IO Support Rebooted&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Tipado en Python: Estructuras de datos</title><link>https://blog.dacadev.com/python/tipado/estructuras-de-datos/</link><pubDate>Tue, 13 Aug 2024 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/tipado/estructuras-de-datos/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende a elegir estructuras de datos tipadas en Python con TypedDict, NotRequired, Required y dataclass para modelos claros.</description><media:content url="https://blog.dacadev.com/images/python/typing/data-structures/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#diccionarios-tipados-en-python"&gt;Diccionarios tipados en Python&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#typeddict-diccionarios-con-forma-definida"&gt;TypedDict: diccionarios con forma definida&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#llaves-opcionales-con-notrequired"&gt;Llaves opcionales con NotRequired&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#enfoque-inverso-totalfalse-y-required"&gt;Enfoque inverso: total=False y Required&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#dataclass-estructuras-de-datos-con-atributos"&gt;Dataclass: estructuras de datos con atributos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#dataclass-vs-class-tradicional"&gt;Dataclass vs class tradicional&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cuándo-usar-cada-estructura-de-datos"&gt;Cuándo usar cada estructura de datos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cierre"&gt;Cierre&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando una función recibe datos de un producto, un usuario o una respuesta de una API, el problema no suele ser solamente el tipo de cada valor, sino la forma completa del objeto. Las &lt;strong&gt;estructuras de datos tipadas en Python&lt;/strong&gt; nos permiten documentar y validar mejor esa forma: qué claves existen, cuáles son opcionales y cuándo conviene pasar de un diccionario a una estructura con comportamiento propio.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;Este artículo es parte de una serie que explica el tipado en Python. A continuación, puedes ver la recopilación de todos los posts de la serie.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/serie-de-tipado" class="btn btn-outline-primary " rel="" &gt;Ver serie&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;En artículos anteriores vimos cómo agregar tipos a variables, colecciones y funciones. Ahora vamos a llevar esa idea a estructuras que representan datos con significado dentro de una aplicación: productos, órdenes, usuarios, configuraciones o payloads de entrada/salida.&lt;/p&gt;
&lt;h2 id="diccionarios-tipados-en-python"&gt;Diccionarios tipados en Python&lt;/h2&gt;
&lt;p&gt;Los diccionarios son una de las formas más comunes de representar datos en Python. Nos permiten asociar llaves con valores, y esas llaves deben ser objetos hashables, normalmente &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt; o tuplas inmutables.&lt;/p&gt;
&lt;p&gt;Para agregar tipado a un diccionario podemos usar &lt;code&gt;dict[&amp;lt;tipo_llave&amp;gt;, &amp;lt;tipo_valor&amp;gt;]&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;dict&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;: &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este ejemplo estamos indicando que las llaves son &lt;code&gt;str&lt;/code&gt; y que los valores pueden ser &lt;code&gt;str&lt;/code&gt; o &lt;code&gt;int&lt;/code&gt;. Esto ayuda a evitar errores como usar una llave de tipo incorrecto o asignar un valor fuera del rango esperado.&lt;/p&gt;
&lt;p&gt;Sin embargo, esta aproximación tiene una limitación importante: &lt;strong&gt;no transmite qué claves se esperan&lt;/strong&gt; dentro del diccionario. El analizador estático sabe que puede existir cualquier llave &lt;code&gt;str&lt;/code&gt;, pero no sabe que esperamos exactamente &lt;code&gt;name&lt;/code&gt; y &lt;code&gt;price&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;dict&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;: &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# ✅ válido&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;category&amp;#34;&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# ✅ también parece válido para el type checker&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El segundo acceso puede fallar en tiempo de ejecución con un &lt;code&gt;KeyError&lt;/code&gt;, pero el tipo &lt;code&gt;dict[str, str | int]&lt;/code&gt; no expresa que &lt;code&gt;category&lt;/code&gt; no hace parte del contrato de esa estructura.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Un diccionario tipado con &lt;code&gt;dict[str, ...]&lt;/code&gt; es útil cuando trabajas con pares clave-valor homogéneos o dinámicos. Cuando necesitas describir una forma específica de datos, conviene usar &lt;code&gt;TypedDict&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="typeddict-diccionarios-con-forma-definida"&gt;TypedDict: diccionarios con forma definida&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;TypedDict&lt;/code&gt;, disponible desde el módulo &lt;a href="https://docs.python.org/3/library/typing.html#typing.TypedDict"




 target="_blank"
 


&gt;&lt;code&gt;typing&lt;/code&gt;&lt;/a&gt;, nos permite definir un diccionario con claves conocidas y valores tipados. Es especialmente útil para payloads JSON, respuestas de APIs o datos que siguen siendo diccionarios, pero tienen una estructura clara.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;TypedDict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Product&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;TypedDict&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Product&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;: &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;: [&lt;span style="color:#98c379"&gt;&amp;#34;ropa&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;active&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Con esta definición, el type checker entiende que &lt;code&gt;Product&lt;/code&gt; debe tener las claves &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt; y &lt;code&gt;active&lt;/code&gt;, y que cada una espera un tipo específico.&lt;/p&gt;
&lt;p&gt;Es importante recordar que &lt;code&gt;TypedDict&lt;/code&gt; &lt;strong&gt;no cambia el comportamiento del diccionario en tiempo de ejecución&lt;/strong&gt;. Seguimos trabajando con un &lt;code&gt;dict&lt;/code&gt;, no con una clase tradicional.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# ✅ funciona&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# ❌ no funciona&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;TypedDict&lt;/code&gt; mejora la información disponible para herramientas como editores, linters y analizadores estáticos. Pero el acceso sigue siendo por llave, igual que en cualquier diccionario.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;No uses &lt;code&gt;TypedDict&lt;/code&gt; esperando validación automática en tiempo de ejecución. Su objetivo principal es mejorar el tipado estático y la documentación del contrato de datos.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="llaves-opcionales-con-notrequired"&gt;Llaves opcionales con NotRequired&lt;/h2&gt;
&lt;p&gt;En muchos casos una estructura tiene campos obligatorios y campos opcionales. Por ejemplo, un producto puede requerir &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt; y &lt;code&gt;active&lt;/code&gt;, pero permitir que &lt;code&gt;tags&lt;/code&gt; no exista.&lt;/p&gt;
&lt;p&gt;Para ese caso podemos usar &lt;code&gt;NotRequired&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;NotRequired&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;TypedDict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Product&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;TypedDict&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;NotRequired&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product_without_tags&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Product&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;: &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;active&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La clave &lt;code&gt;tags&lt;/code&gt; ahora puede omitirse. Esto es diferente a decir que &lt;code&gt;tags&lt;/code&gt; puede ser &lt;code&gt;None&lt;/code&gt;. Con &lt;code&gt;NotRequired[list[str]]&lt;/code&gt;, la llave completa puede no existir.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Product&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;TypedDict&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;NotRequired&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Product&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {&lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ✅ acceso seguro si la llave puede no existir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# ⚠️ puede lanzar KeyError en tiempo de ejecución&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si una llave es opcional, usa &lt;code&gt;get()&lt;/code&gt; o valida su existencia antes de acceder con &lt;code&gt;[]&lt;/code&gt;. El tipado te ayuda a diseñar el contrato, pero no elimina los errores de acceso en tiempo de ejecución.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="enfoque-inverso-totalfalse-y-required"&gt;Enfoque inverso: total=False y Required&lt;/h2&gt;
&lt;p&gt;También podemos definir el caso contrario: que todas las llaves sean opcionales por defecto y marcar únicamente algunas como obligatorias. Para ello usamos &lt;code&gt;total=False&lt;/code&gt; junto con &lt;code&gt;Required&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Required&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;TypedDict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Product&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;TypedDict&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;total&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;False&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Required&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Required&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Product&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;: &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aquí &lt;code&gt;name&lt;/code&gt; y &lt;code&gt;price&lt;/code&gt; son obligatorias, mientras que &lt;code&gt;tags&lt;/code&gt; y &lt;code&gt;active&lt;/code&gt; pueden omitirse. Este enfoque es útil cuando la mayoría de campos son opcionales y solo necesitas destacar unos pocos como requeridos.&lt;/p&gt;
&lt;p&gt;La decisión entre &lt;code&gt;NotRequired&lt;/code&gt; y &lt;code&gt;total=False + Required&lt;/code&gt; depende de la forma dominante de tu estructura:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usa &lt;code&gt;NotRequired&lt;/code&gt; cuando la mayoría de campos son obligatorios.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;total=False + Required&lt;/code&gt; cuando la mayoría de campos son opcionales.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dataclass-estructuras-de-datos-con-atributos"&gt;Dataclass: estructuras de datos con atributos&lt;/h2&gt;
&lt;p&gt;Una &lt;a href="https://docs.python.org/3/library/dataclasses.html"




 target="_blank"
 


&gt;&lt;code&gt;dataclass&lt;/code&gt;&lt;/a&gt; es una clase diseñada para almacenar datos con menos código repetitivo. Python agregó este decorador en la versión 3.7, y desde entonces se convirtió en una herramienta muy práctica para modelar objetos de datos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;dataclasses&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;dataclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef"&gt;@dataclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Product&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Product&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;20&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;ropa&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;price&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A diferencia de &lt;code&gt;TypedDict&lt;/code&gt;, aquí sí accedemos a los datos como atributos: &lt;code&gt;product.name&lt;/code&gt;, &lt;code&gt;product.price&lt;/code&gt;, &lt;code&gt;product.tags&lt;/code&gt;. Además, &lt;code&gt;dataclass&lt;/code&gt; genera automáticamente métodos como &lt;code&gt;__init__&lt;/code&gt;, &lt;code&gt;__repr__&lt;/code&gt; y &lt;code&gt;__eq__&lt;/code&gt;, lo que reduce la cantidad de código necesario.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product_1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Product&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;20&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;ropa&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product_2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Product&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;20&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;ropa&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;product_1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;==&lt;/span&gt; &lt;span style="color:#e06c75"&gt;product_2&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;product_1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# Product(name=&amp;#39;Camisa&amp;#39;, price=20, active=True, tags=[&amp;#39;ropa&amp;#39;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;dataclass&lt;/code&gt; sigue siendo una clase de Python. El decorador solo genera código común por ti, sin impedir que agregues métodos, validaciones o comportamiento adicional cuando lo necesites.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="dataclass-vs-class-tradicional"&gt;Dataclass vs class tradicional&lt;/h2&gt;
&lt;p&gt;Podemos escribir una clase tradicional para representar el mismo producto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Product&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;price&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;active&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;tags&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El código funciona, pero gran parte de la implementación es repetitiva. Solo estamos recibiendo argumentos y asignándolos como atributos. Con &lt;code&gt;dataclass&lt;/code&gt;, expresamos la misma estructura de forma más directa:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;dataclasses&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;dataclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef"&gt;@dataclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Product&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La diferencia no es solamente estética. &lt;code&gt;dataclass&lt;/code&gt; comunica intención: esta clase existe principalmente para alojar datos. Además, mantiene una buena integración con type hints y reduce el riesgo de inconsistencias entre los argumentos de &lt;code&gt;__init__&lt;/code&gt; y los atributos reales.&lt;/p&gt;
&lt;p&gt;También puedes agregar comportamiento cuando haga falta:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;dataclasses&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;dataclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef"&gt;@dataclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Product&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;has_tag&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tag&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;tag&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;product&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Product&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;Camisa&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;price&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;20&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;active&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tags&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;ropa&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;product&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;has_tag&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;ropa&amp;#34;&lt;/span&gt;)) &lt;span style="color:#7f848e"&gt;# True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si tu clase solo define &lt;code&gt;__init__&lt;/code&gt;, &lt;code&gt;__repr__&lt;/code&gt; o comparaciones básicas para alojar datos, probablemente una &lt;code&gt;dataclass&lt;/code&gt; expresa mejor la intención.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cuándo-usar-cada-estructura-de-datos"&gt;Cuándo usar cada estructura de datos&lt;/h2&gt;
&lt;p&gt;No existe una única estructura correcta para todos los casos. La decisión depende de si estás modelando datos dinámicos, contratos de intercambio o entidades con comportamiento.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A[Necesitas representar datos con estructura] --&gt; B{¿Debe seguir siendo un dict?}
 B -- Sí --&gt; C{¿Conoces las claves esperadas?}
 C -- No --&gt; D["Usa dict[str, tipo]"]
 C -- Sí --&gt; E[Usa TypedDict]
 B -- No --&gt; F{¿Principalmente almacena datos?}
 F -- Sí --&gt; G[Usa dataclass]
 F -- No --&gt; H[Usa class tradicional]
&lt;/pre&gt;

&lt;p&gt;Como regla práctica:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;dict[str, tipo]&lt;/code&gt;&lt;/strong&gt;: úsalo cuando las claves son dinámicas o la estructura es homogénea. Por ejemplo, contadores, mapas de configuración simples o agrupaciones donde todas las llaves comparten el mismo tipo de valor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TypedDict&lt;/code&gt;&lt;/strong&gt;: úsalo cuando necesitas conservar el comportamiento de diccionario, pero quieres describir claves específicas. Es una buena opción para JSON, payloads de APIs y datos serializables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;dataclass&lt;/code&gt;&lt;/strong&gt;: úsala cuando quieres representar datos con atributos, comparación automática y una intención clara de modelo de datos. Funciona muy bien para capas internas de dominio o estructuras intermedias.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;class&lt;/code&gt; tradicional&lt;/strong&gt;: úsala cuando el objeto necesita controlar invariantes complejas, encapsular estado mutable o exponer comportamiento más importante que los datos que almacena.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La frontera entre &lt;code&gt;dataclass&lt;/code&gt; y &lt;code&gt;class&lt;/code&gt; tradicional no es rígida. Una &lt;code&gt;dataclass&lt;/code&gt; puede tener métodos, y una clase tradicional puede almacenar datos. La clave está en comunicar intención y evitar código accidentalmente complejo.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;No conviertas todo diccionario en &lt;code&gt;dataclass&lt;/code&gt; ni todo objeto en &lt;code&gt;TypedDict&lt;/code&gt;. Elige la estructura según el contrato que quieres expresar y el comportamiento que necesitas en el sistema.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cierre"&gt;Cierre&lt;/h2&gt;
&lt;p&gt;Las estructuras de datos tipadas en Python nos ayudan a hacer explícitos los contratos que antes quedaban implícitos en diccionarios o clases repetitivas. &lt;code&gt;dict[str, ...]&lt;/code&gt; funciona para casos homogéneos, &lt;code&gt;TypedDict&lt;/code&gt; describe diccionarios con forma específica, &lt;code&gt;NotRequired&lt;/code&gt; y &lt;code&gt;Required&lt;/code&gt; permiten modelar campos opcionales, y &lt;code&gt;dataclass&lt;/code&gt; reduce el código necesario para representar datos con atributos.&lt;/p&gt;
&lt;p&gt;Lo importante es usar el tipado como una herramienta de diseño. Cuando la estructura comunica intención, el código se vuelve más fácil de leer, refactorizar y validar antes de llegar a producción.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;Esta es la pieza final de la serie hasta el momento. Puedes volver a la recopilación completa para repasar los conceptos anteriores sobre tipado en Python.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/serie-de-tipado" class="btn btn-outline-primary " rel="" &gt;Ver serie&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</content:encoded></item><item><title>Tipado en Python: Tipado de clases</title><link>https://blog.dacadev.com/python/tipado/tipado-clases/</link><pubDate>Mon, 12 Aug 2024 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/tipado/tipado-clases/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende tipado de clases en Python con ClassVar, Self y referencias diferidas para modelar objetos más claros y seguros.</description><media:content url="https://blog.dacadev.com/images/python/typing/classes/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#usar-clases-como-tipos-en-python"&gt;Usar clases como tipos en Python&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tipar-atributos-de-instancia-en-la-clase"&gt;Tipar atributos de instancia en la clase&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#classvar-para-variables-de-clase"&gt;ClassVar para variables de clase&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias-hacia-la-propia-clase-con-strings"&gt;Referencias hacia la propia clase con strings&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#evaluación-diferida-con-from-__future__-import-annotations"&gt;Evaluación diferida con &lt;code&gt;from __future__ import annotations&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#typingself-para-métodos-que-devuelven-la-misma-clase"&gt;&lt;code&gt;typing.Self&lt;/code&gt; para métodos que devuelven la misma clase&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#herencia-cuando-la-clase-base-no-es-suficiente"&gt;Herencia: cuando la clase base no es suficiente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cierre"&gt;Cierre&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando un proyecto empieza a tener modelos de dominio, servicios y objetos que se pasan entre capas, el &lt;strong&gt;tipado de clases en Python&lt;/strong&gt; se vuelve una herramienta clave para mantener contratos claros. Ya no se trata solo de saber si una variable es &lt;code&gt;str&lt;/code&gt; o &lt;code&gt;int&lt;/code&gt;; también necesitamos expresar que un método recibe un &lt;code&gt;User&lt;/code&gt;, que un atributo guarda un &lt;code&gt;datetime&lt;/code&gt;, o que una operación entre contadores devuelve otro contador compatible.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;Este artículo es parte de una serie que explica el tipado en Python. A continuación, puedes ver la recopilación de todos los posts de la serie.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/serie-de-tipado" class="btn btn-outline-primary " rel="" &gt;Ver serie&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;En esta entrega nos concentraremos en clases: cómo usarlas como tipos, cómo declarar atributos de instancia, cuándo aplicar &lt;code&gt;ClassVar&lt;/code&gt;, y cómo resolver referencias hacia la propia clase con strings, &lt;code&gt;from __future__ import annotations&lt;/code&gt; y &lt;code&gt;typing.Self&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="usar-clases-como-tipos-en-python"&gt;Usar clases como tipos en Python&lt;/h2&gt;
&lt;p&gt;En Python, una clase también puede usarse como anotación de tipo. Esto aplica tanto para clases que tú defines como para clases de la librería estándar. Por ejemplo, el módulo &lt;a href="https://docs.python.org/3/library/datetime.html"




 target="_blank"
 


&gt;&lt;code&gt;datetime&lt;/code&gt;&lt;/a&gt; define tipos como &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;datetime&lt;/code&gt; y &lt;code&gt;timedelta&lt;/code&gt;, mientras que &lt;a href="https://docs.python.org/3/library/uuid.html"




 target="_blank"
 


&gt;&lt;code&gt;uuid&lt;/code&gt;&lt;/a&gt; define &lt;code&gt;UUID&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;uuid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;birth_date&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;date&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;date&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2020&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;7&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;timestamp&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2020&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;7&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;duration&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;timedelta&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;timedelta&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;hours&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;uid1&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;uuid&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;UUID&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;uuid&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;uuid1&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;uid4&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;uuid&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;UUID&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;uuid&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;uuid4&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Este código no cambia el comportamiento en tiempo de ejecución. Su valor está en la señal que le entregamos al IDE, al analizador estático y a otros desarrolladores que lean el código.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;created_at&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;datetime&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;now&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;created_at&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;2024-08-12&amp;#34;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# ❌ el contrato dejó de ser datetime.datetime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Las anotaciones no reemplazan la validación de datos externos. Si recibes JSON, entrada de usuario o información desde una API, sigue siendo necesario validar en los bordes del sistema.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="tipar-atributos-de-instancia-en-la-clase"&gt;Tipar atributos de instancia en la clase&lt;/h2&gt;
&lt;p&gt;Cuando trabajamos con clases propias, podemos declarar los atributos esperados directamente en el cuerpo de la clase. Esto ayuda a que el analizador entienda qué atributos existen en cada instancia, incluso si se asignan dentro de &lt;code&gt;__init__&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Counter&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__repr__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este ejemplo, &lt;code&gt;n: int&lt;/code&gt; describe un &lt;strong&gt;atributo de instancia&lt;/strong&gt;. Cada objeto &lt;code&gt;Counter&lt;/code&gt; tendrá su propio valor de &lt;code&gt;n&lt;/code&gt;, asignado en el constructor.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;start&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;counter&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ✅ 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;repr&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;counter&lt;/span&gt;)) &lt;span style="color:#7f848e"&gt;# ✅ &amp;#34;10&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# ❌ rompe el contrato declarado para la instancia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La anotación en el cuerpo de la clase no inicializa el atributo por sí sola. Si declaras &lt;code&gt;n: int&lt;/code&gt;, pero nunca asignas &lt;code&gt;self.n&lt;/code&gt;, la instancia no tendrá ese atributo disponible en tiempo de ejecución.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Anotar un atributo no es lo mismo que crearlo. La anotación describe el contrato; la asignación en &lt;code&gt;__init__&lt;/code&gt; crea el estado real de la instancia.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="classvar-para-variables-de-clase"&gt;ClassVar para variables de clase&lt;/h2&gt;
&lt;p&gt;No todos los atributos declarados en una clase pertenecen a cada instancia. Algunas variables funcionan como configuración compartida para todas las instancias. Para estos casos existe &lt;a href="https://docs.python.org/3/library/typing.html#typing.ClassVar"




 target="_blank"
 


&gt;&lt;code&gt;ClassVar&lt;/code&gt;&lt;/a&gt;, disponible desde &lt;code&gt;typing&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ClassVar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Counter&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;STEP&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;ClassVar&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__repr__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;increment&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;STEP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;STEP&lt;/code&gt; representa una &lt;strong&gt;variable de clase&lt;/strong&gt;. El valor vive en la clase &lt;code&gt;Counter&lt;/code&gt;, no como parte del estado individual de cada objeto.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;STEP&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# ✅ configuración compartida&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;increment&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;counter&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;STEP&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;5&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# ❌ puede ocultar la variable de clase en esa instancia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Técnicamente Python permite asignar &lt;code&gt;counter.STEP = 5&lt;/code&gt;, pero eso crea o modifica un atributo en la instancia, lo cual puede generar confusión. &lt;code&gt;ClassVar&lt;/code&gt; permite que herramientas como mypy o Pyright detecten este uso como una señal de diseño incorrecta.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;ClassVar&lt;/code&gt; cuando el atributo describe configuración, constantes o metadatos compartidos por todas las instancias de una clase.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="referencias-hacia-la-propia-clase-con-strings"&gt;Referencias hacia la propia clase con strings&lt;/h2&gt;
&lt;p&gt;Un caso común aparece cuando un método recibe o devuelve otra instancia de la misma clase. Por ejemplo, podemos definir la suma de dos contadores con &lt;code&gt;__add__&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ClassVar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Counter&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;STEP&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;ClassVar&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__repr__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__add__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;Counter&amp;#34;&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Counter&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;start&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La anotación &lt;code&gt;&amp;quot;Counter&amp;quot;&lt;/code&gt; es una &lt;strong&gt;referencia adelantada&lt;/strong&gt; o &lt;em&gt;forward reference&lt;/em&gt;. Se escribe como string porque, mientras Python está evaluando el cuerpo de la clase, el nombre &lt;code&gt;Counter&lt;/code&gt; todavía no terminó de definirse.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;first&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;second&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;result&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;first&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;second&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;result&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El siguiente diagrama resume el contrato principal de la clase:&lt;/p&gt;
&lt;pre class="mermaid"&gt;classDiagram
 class Counter {
 +int n
 +ClassVar~int~ STEP
 +__init__(int start) None
 +__repr__() str
 +__add__(Counter other) Counter
 }
&lt;/pre&gt;

&lt;p&gt;Esta forma es compatible con versiones antiguas de Python y sigue siendo frecuente en bases de código que necesitan soportar varios entornos.&lt;/p&gt;
&lt;h2 id="evaluación-diferida-con-from-__future__-import-annotations"&gt;Evaluación diferida con &lt;code&gt;from __future__ import annotations&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Desde Python 3.7 podemos activar la evaluación diferida de anotaciones usando &lt;code&gt;from __future__ import annotations&lt;/code&gt;. Con esto, las anotaciones no se resuelven inmediatamente al definir la clase, lo que permite escribir &lt;code&gt;Counter&lt;/code&gt; sin comillas.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;__future__&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;annotations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ClassVar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Counter&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;STEP&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;ClassVar&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__repr__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__add__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;start&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La ventaja principal es legibilidad. El código se ve más cercano a una anotación normal y reduce el ruido de comillas en modelos con muchas referencias cruzadas.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# ✅ con evaluación diferida&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;__future__&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;annotations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Node&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;parent&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Node&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;parent&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Node&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;parent&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;parent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;from __future__ import annotations&lt;/code&gt; debe aparecer al inicio del archivo, antes de otros imports normales. Es una decisión por módulo, no por clase.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="typingself-para-métodos-que-devuelven-la-misma-clase"&gt;&lt;code&gt;typing.Self&lt;/code&gt; para métodos que devuelven la misma clase&lt;/h2&gt;
&lt;p&gt;Python 3.11 incorporó &lt;a href="https://docs.python.org/3/library/typing.html#typing.Self"




 target="_blank"
 


&gt;&lt;code&gt;typing.Self&lt;/code&gt;&lt;/a&gt; para expresar que un método devuelve una instancia del mismo tipo concreto que lo invoca. Esto es especialmente útil en métodos fluidos, constructores alternativos y operaciones que deberían preservar el subtipo.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Counter&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__repr__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__add__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Self&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;type&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;)(&lt;span style="color:#e06c75"&gt;start&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aquí usamos &lt;code&gt;type(self)(...)&lt;/code&gt; en lugar de &lt;code&gt;Counter(...)&lt;/code&gt; para respetar el tipo concreto de la instancia. Si más adelante existe una subclase de &lt;code&gt;Counter&lt;/code&gt;, el método tiene mejores posibilidades de devolver esa misma subclase.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si anotas un método con &lt;code&gt;Self&lt;/code&gt;, procura que la implementación realmente devuelva el mismo tipo concreto. Anotar &lt;code&gt;Self&lt;/code&gt; pero retornar siempre &lt;code&gt;Counter(...)&lt;/code&gt; puede engañar al analizador estático.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="herencia-cuando-la-clase-base-no-es-suficiente"&gt;Herencia: cuando la clase base no es suficiente&lt;/h2&gt;
&lt;p&gt;El beneficio de &lt;code&gt;Self&lt;/code&gt; se ve más claro con herencia. Consideremos una clase base &lt;code&gt;A&lt;/code&gt; y una subclase &lt;code&gt;B&lt;/code&gt;. Si el método &lt;code&gt;me&lt;/code&gt; se anota devolviendo &lt;code&gt;A&lt;/code&gt;, el tipo estático del resultado será siempre &lt;code&gt;A&lt;/code&gt;, incluso cuando el objeto real sea &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;__future__&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;annotations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;A&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;me&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;A&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;B&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;A&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;B&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;result&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;me&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# tipo estático: A&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ese contrato es correcto, pero pierde información. El método devuelve &lt;code&gt;self&lt;/code&gt;, así que cuando lo invoca una instancia de &lt;code&gt;B&lt;/code&gt;, el resultado debería conservar el tipo &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;A&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;me&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Self&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;B&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;A&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;B&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;result&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;me&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# tipo estático: B&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La diferencia es importante cuando encadenas métodos o cuando la subclase agrega comportamiento adicional.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;A&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;me&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Self&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;B&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;A&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;only_b&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;B&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;b&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;me&lt;/span&gt;()&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;only_b&lt;/span&gt;()) &lt;span style="color:#7f848e"&gt;# ✅ el analizador conserva que b.me() es B&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sin &lt;code&gt;Self&lt;/code&gt;, el analizador puede asumir que &lt;code&gt;b.me()&lt;/code&gt; es &lt;code&gt;A&lt;/code&gt;, y por tanto marcar &lt;code&gt;only_b()&lt;/code&gt; como un método inexistente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;A&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;me&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;B&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;A&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;only_b&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;B&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;me&lt;/span&gt;()&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;only_b&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# ❌ para el analizador, me() devuelve A&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;Self&lt;/code&gt; cuando el contrato del método sea “devuelvo el mismo tipo concreto que recibió la llamada”. Usa el nombre de la clase cuando el método debe devolver explícitamente una instancia de esa clase base.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cierre"&gt;Cierre&lt;/h2&gt;
&lt;p&gt;El tipado de clases permite expresar contratos más precisos entre objetos. Puedes usar clases estándar como &lt;code&gt;datetime.datetime&lt;/code&gt; o &lt;code&gt;uuid.UUID&lt;/code&gt;, declarar atributos de instancia, diferenciar variables compartidas con &lt;code&gt;ClassVar&lt;/code&gt;, y manejar referencias hacia la propia clase con strings o evaluación diferida.&lt;/p&gt;
&lt;p&gt;Para jerarquías de herencia, &lt;code&gt;typing.Self&lt;/code&gt; mejora la precisión del análisis estático porque conserva el tipo concreto de la instancia. Esta diferencia se vuelve relevante cuando diseñas APIs orientadas a objetos, métodos encadenables o modelos que se especializan mediante subclases.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;En el próximo artículo veremos cómo aplicar tipado a estructuras de datos para modelar colecciones más expresivas y mantenibles.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/estructuras-de-datos" class="btn btn-outline-primary " rel="" &gt;Estructuras de datos&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</content:encoded></item><item><title>Tipado en Python: Tipado de funciones</title><link>https://blog.dacadev.com/python/tipado/tipado-funciones/</link><pubDate>Sun, 11 Aug 2024 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/tipado/tipado-funciones/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende tipado de funciones en Python con type hints, valores por defecto, *args y Callable mediante ejemplos prácticos.</description><media:content url="https://blog.dacadev.com/images/python/typing/functions/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#sintaxis-general-para-tipar-funciones"&gt;Sintaxis general para tipar funciones&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#ejemplo-con-counter"&gt;Ejemplo con &lt;code&gt;Counter&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#valores-por-defecto-tipados"&gt;Valores por defecto tipados&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#args-tipados"&gt;&lt;code&gt;*args&lt;/code&gt; tipados&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#args-con-parámetros-keyword-only"&gt;&lt;code&gt;*args&lt;/code&gt; con parámetros keyword-only&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#funciones-de-primer-orden-y-callable"&gt;Funciones de primer orden y &lt;code&gt;Callable&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#callable-con-clases-y-__call__"&gt;&lt;code&gt;Callable&lt;/code&gt; con clases y &lt;code&gt;__call__&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando un módulo crece y varias funciones empiezan a pasar datos entre capas, el contrato entre parámetros y retorno se vuelve crítico. El &lt;strong&gt;tipado de funciones en Python&lt;/strong&gt; nos permite documentar ese contrato directamente en el código, mejorar la autocompletación del IDE y detectar inconsistencias antes de ejecutar el flujo completo en producción.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;Este artículo es parte de una serie que explica el tipado en Python. A continuación, puedes ver la recopilación de todos los posts de la serie.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/serie-de-tipado" class="btn btn-outline-primary " rel="" &gt;Ver serie&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;En la entrega anterior vimos cómo anotar variables y colecciones. Ahora aplicaremos esa misma idea en funciones: parámetros, retornos, valores por defecto, argumentos dinámicos y objetos que se pueden invocar como funciones.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Las anotaciones de tipo no cambian el comportamiento de Python en tiempo de ejecución. Su valor principal está en herramientas de análisis estático como &lt;code&gt;mypy&lt;/code&gt;, &lt;code&gt;pyright&lt;/code&gt;, IDEs y revisiones de código.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="sintaxis-general-para-tipar-funciones"&gt;Sintaxis general para tipar funciones&lt;/h2&gt;
&lt;p&gt;La sintaxis base para agregar tipos a una función consiste en anotar cada argumento después de &lt;code&gt;:&lt;/code&gt; y declarar el tipo de retorno después de &lt;code&gt;-&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;my_function&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;arg1&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;type&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;arg2&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;type&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;return_type&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#56b6c2"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Esta estructura expresa dos cosas importantes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;arg1: type&lt;/code&gt;: el argumento &lt;code&gt;arg1&lt;/code&gt; debería recibir valores compatibles con &lt;code&gt;type&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&amp;gt; return_type&lt;/code&gt;: la función debería devolver un valor compatible con &lt;code&gt;return_type&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Por ejemplo, una función que recibe dos enteros y retorna otro entero se puede escribir así:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;add&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si la función no retorna un valor útil, se usa &lt;code&gt;None&lt;/code&gt; como tipo de retorno:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;log_message&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Anotar el retorno es tan importante como anotar los argumentos. Muchas inconsistencias aparecen cuando una función empieza devolviendo &lt;code&gt;int&lt;/code&gt;, luego en una rama retorna &lt;code&gt;None&lt;/code&gt; y el consumidor asume que siempre puede operar con números.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="ejemplo-con-counter"&gt;Ejemplo con &lt;code&gt;Counter&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Supongamos que tenemos una lista de elementos y cada elemento contiene una lista de etiquetas. Queremos contar cuántas veces aparece cada etiqueta.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;counter_tags&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;items&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;dict&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]]]) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Counter&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;tag&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;item&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;items&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;tag&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;item&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La firma de &lt;code&gt;counter_tags&lt;/code&gt; nos dice que &lt;code&gt;items&lt;/code&gt; debe ser una lista de diccionarios. Cada diccionario usa llaves de tipo &lt;code&gt;str&lt;/code&gt; y valores de tipo &lt;code&gt;list[str]&lt;/code&gt;. La función retorna un &lt;code&gt;Counter[str]&lt;/code&gt;, es decir, un contador cuyas llaves son cadenas.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter_tags&lt;/span&gt;([{&lt;span style="color:#98c379"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;: [&lt;span style="color:#98c379"&gt;&amp;#34;python&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;typing&amp;#34;&lt;/span&gt;]}, {&lt;span style="color:#98c379"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;: [&lt;span style="color:#98c379"&gt;&amp;#34;python&amp;#34;&lt;/span&gt;]}]) &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter_tags&lt;/span&gt;([{&lt;span style="color:#98c379"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;: [&lt;span style="color:#98c379"&gt;&amp;#34;python&amp;#34;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;]}, {&lt;span style="color:#98c379"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;: [&lt;span style="color:#98c379"&gt;&amp;#34;typing&amp;#34;&lt;/span&gt;]}]) &lt;span style="color:#7f848e"&gt;# ❌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La segunda llamada es problemática porque la lista de &lt;code&gt;tags&lt;/code&gt; mezcla &lt;code&gt;str&lt;/code&gt; con &lt;code&gt;int&lt;/code&gt;. Python puede ejecutarla, pero un analizador estático marcará que &lt;code&gt;1&lt;/code&gt; no coincide con &lt;code&gt;list[str]&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;El tipado describe la forma esperada de los datos, pero no reemplaza validaciones de entrada cuando los datos vienen de usuarios, APIs externas, archivos o mensajes de una cola.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="valores-por-defecto-tipados"&gt;Valores por defecto tipados&lt;/h2&gt;
&lt;p&gt;Cuando una función tiene valores por defecto, también conviene anotar esos parámetros. El valor asignado debe ser compatible con el tipo declarado.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;sum_numbers&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;], &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_numbers&lt;/span&gt;([&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;], &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;100&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_numbers&lt;/span&gt;([&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;]) &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_numbers&lt;/span&gt;([&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;]) &lt;span style="color:#7f848e"&gt;# ❌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_numbers&lt;/span&gt;([&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;], &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ❌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este caso &lt;code&gt;numbers&lt;/code&gt; debe ser una lista de enteros y &lt;code&gt;start&lt;/code&gt; también debe ser un entero. Si no se pasa &lt;code&gt;start&lt;/code&gt;, Python usa &lt;code&gt;0&lt;/code&gt;, que cumple con la anotación &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Este patrón es útil en funciones acumuladoras, paginadores, transformaciones de datos y cualquier API interna donde un valor opcional modifica el cálculo sin cambiar el tipo esperado.&lt;/p&gt;
&lt;h2 id="args-tipados"&gt;&lt;code&gt;*args&lt;/code&gt; tipados&lt;/h2&gt;
&lt;p&gt;Python permite recibir una cantidad variable de argumentos posicionales con &lt;code&gt;*args&lt;/code&gt;. Para tiparlos, se anota el tipo de cada elemento recibido, no el tipo de la tupla completa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;sum_args&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;args&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;args&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_args&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_args&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ❌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La anotación &lt;code&gt;*args: int&lt;/code&gt; significa que cada argumento posicional adicional debe ser &lt;code&gt;int&lt;/code&gt;. Internamente, Python sigue recibiendo una tupla, pero desde el punto de vista del contrato de la función, cada elemento debe respetar el tipo indicado.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si necesitas aceptar varios tipos en &lt;code&gt;*args&lt;/code&gt;, puedes combinar tipos con &lt;code&gt;|&lt;/code&gt;, por ejemplo &lt;code&gt;*args: int | float&lt;/code&gt;. Esto mantiene el contrato explícito sin convertir la función en una entrada completamente abierta.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="args-con-parámetros-keyword-only"&gt;&lt;code&gt;*args&lt;/code&gt; con parámetros keyword-only&lt;/h2&gt;
&lt;p&gt;También podemos combinar argumentos dinámicos con parámetros que solo se reciben por nombre. En Python, todo parámetro declarado después de &lt;code&gt;*args&lt;/code&gt; se vuelve &lt;strong&gt;keyword-only&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;sum_args&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;args&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;args&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_args&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_args&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;100&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_args&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ❌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum_args&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ❌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aquí &lt;code&gt;start&lt;/code&gt; no puede pasarse como otro argumento posicional más; debe enviarse usando su nombre. Esto mejora la legibilidad cuando el parámetro tiene un rol especial dentro del cálculo.&lt;/p&gt;
&lt;p&gt;Este estilo es recomendable cuando una función acepta una secuencia flexible de valores, pero también necesita opciones de configuración con nombres claros.&lt;/p&gt;
&lt;h2 id="funciones-de-primer-orden-y-callable"&gt;Funciones de primer orden y &lt;code&gt;Callable&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;En Python podemos pasar funciones como argumentos de otras funciones. Para anotar este tipo de contrato usamos &lt;code&gt;Callable&lt;/code&gt;, disponible en &lt;a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable"




 target="_blank"
 


&gt;&lt;code&gt;collections.abc&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections.abc&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;work&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;send_notification&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;[[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;], &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;]) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;i&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;send_notification&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;Finished &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;i&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; rounds of work!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La anotación &lt;code&gt;Callable[[str], None]&lt;/code&gt; indica que &lt;code&gt;send_notification&lt;/code&gt; debe ser invocable, recibir un &lt;code&gt;str&lt;/code&gt; y no retornar un valor útil.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;notify&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;bad_notify&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;work&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;notify&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;work&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;bad_notify&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ❌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En &lt;code&gt;Callable&lt;/code&gt;, el primer bloque define la lista de argumentos y el segundo define el retorno:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;[[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;], &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;[[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;], &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;[[&lt;span style="color:#e5c07b"&gt;bytes&lt;/span&gt;], &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre class="mermaid"&gt;flowchart LR
 A["Callable[[str, int], bool]"] --&gt; B[Entrada 1: str]
 A --&gt; C[Entrada 2: int]
 B --&gt; D[Función compatible]
 C --&gt; D
 D --&gt; E[Salida: bool]
&lt;/pre&gt;





 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;Callable&lt;/code&gt; cuando la función consumidora solo necesita ejecutar un comportamiento. Esto reduce acoplamiento porque no obliga a depender de una implementación concreta.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="callable-con-clases-y-__call__"&gt;&lt;code&gt;Callable&lt;/code&gt; con clases y &lt;code&gt;__call__&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Callable&lt;/code&gt; no se limita a funciones definidas con &lt;code&gt;def&lt;/code&gt;. Una instancia de clase también puede ser invocable si implementa el método especial &lt;code&gt;__call__&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Notifier&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__call__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;message&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;Notifier sends: &amp;#39;&lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;notifier&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Notifier&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;work&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;notifier&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este ejemplo, &lt;code&gt;notifier&lt;/code&gt; se comporta como una función porque &lt;code&gt;Notifier&lt;/code&gt; define &lt;code&gt;__call__&lt;/code&gt;. Para el contrato de &lt;code&gt;work&lt;/code&gt;, lo importante es que el objeto pueda invocarse con un &lt;code&gt;str&lt;/code&gt; y retornar &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Este patrón aparece con frecuencia cuando necesitas combinar estado interno con una interfaz funcional. Por ejemplo, un notificador podría guardar credenciales, configuración del canal o métricas, pero seguir exponiendo una firma simple para el consumidor.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;No confundas &lt;code&gt;Callable&lt;/code&gt; con una clase específica. &lt;code&gt;Callable[[str], None]&lt;/code&gt; describe una capacidad de invocación; no exige que el objeto sea una función tradicional ni una instancia de una clase concreta.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;El tipado de funciones en Python permite hacer explícitos los contratos entre piezas de código: qué argumentos acepta una función, qué retorna y qué forma deben tener los callables que recibe como dependencias.&lt;/p&gt;
&lt;p&gt;En código de aplicación, estas anotaciones mejoran la navegación, reducen errores de integración y facilitan refactors. En librerías o módulos compartidos, además funcionan como documentación ejecutable para otros desarrolladores y herramientas.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;En el siguiente artículo continuaremos con el tipado aplicado a clases, atributos y métodos.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/tipado-clases" class="btn btn-outline-primary " rel="" &gt;Tipado en clases&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</content:encoded></item><item><title>Tipado básico en Python</title><link>https://blog.dacadev.com/python/tipado/tipado-basico/</link><pubDate>Sat, 10 Aug 2024 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/tipado/tipado-basico/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende a aplicar tipos en Python de manera efectiva. Descubre cómo agregar tipado en variables, colecciones, y funciones en Python. Incluye ejemplos prácticos y recomendaciones según la versión de Python.</description><media:content url="https://blog.dacadev.com/images/python/typing/bases/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#tipos-buitl-in-in-python"&gt;Tipos Buitl-in in Python&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tipado-en-colecciones"&gt;Tipado en colecciones&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#combinación-de-tipos-en-python"&gt;Combinación de Tipos en Python&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#definir-más-de-un-tipo"&gt;Definir Más de un Tipo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#valores-opcionales-o-none"&gt;Valores Opcionales o &lt;code&gt;None&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#definir-valores-fijos"&gt;Definir Valores Fijos&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#definir-tipos-personalizados"&gt;Definir Tipos Personalizados&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#datos-io-en-python"&gt;Datos IO en Python&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;Este artículo es parte de una serie que explica el tipado en Python. A continuación, puedes ver la recopilación de todos los posts de la serie.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/serie-de-tipado" class="btn btn-outline-primary " rel="" &gt;Ver serie&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Agregar tipos en Python es muy sencillo y tiene una sintaxis similar a otros lenguajes como &lt;em&gt;Typescript&lt;/em&gt;. &lt;strong&gt;No es obligatorio&lt;/strong&gt; aplicar tipado en cada pieza de código, lo que permite agregarlo de manera gradual. Además, agregar o no tipos no afectará el comportamiento del código.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;La posibilidad de agregar tipado en Python está disponible desde la versión &lt;strong&gt;3.5&lt;/strong&gt;. Desde entonces, se han añadido nuevas características y mejoras.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="tipos-buitl-in-in-python"&gt;Tipos Buitl-in in Python&lt;/h2&gt;
&lt;p&gt;Los tipos &lt;em&gt;built-in&lt;/em&gt; son aquellos que vienen por defecto en Python, como &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;bytes&lt;/code&gt;, &lt;code&gt;None&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;dict&lt;/code&gt;, &lt;code&gt;tuple&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;, entre otros.&lt;/p&gt;
&lt;p&gt;Para agregar tipado a una variable, simplemente añade &lt;code&gt;:&lt;/code&gt; después del nombre de la variable y luego especifica el tipo de dato. La sintaxis es:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;variable&amp;gt;: &amp;lt;type&amp;gt; = &amp;lt;value&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Ejemplo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;f&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;float&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;c&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;complex&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;&lt;span style="color:#e06c75"&gt;j&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;s&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bytes&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;b&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;bytes&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;t&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;v&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En el anterior ejemplo estamos definiendo que cada una de las variables solo van a manejar un tipo de datos a lo largo de vida en el programa.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Recuerda que el agregar el tipo de dato no afecta el comportamiento del código, es solo una ayuda para el programador, analizadores de código estáticos e IDEs.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="tipado-en-colecciones"&gt;Tipado en colecciones&lt;/h2&gt;
&lt;p&gt;Para colecciones como &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;dict&lt;/code&gt;, &lt;code&gt;tuple&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;, la sintaxis es similar a la de las variables simples. salvo que podemos definir o nor el tipo de variable que cada variable va a contener. es decir que tenemos dos tipos de sintaxis que podemos utilizar.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;variable&amp;gt;: &amp;lt;collection&amp;gt; = &amp;lt;value&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;variable&amp;gt;: &amp;lt;collection&amp;gt;[&amp;lt;type&amp;gt;...] = &amp;lt;value&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En la primera opción estamos definiendo que la variable va a ser de tipo &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;dict&lt;/code&gt;, &lt;code&gt;tuple&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt; y en la segunda opción estamos definiendo que la variable va a ser de tipo &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;dict&lt;/code&gt;, &lt;code&gt;tuple&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt; y que va a contener un tipo de dato especifico. Veamos como se aplica esto en algunos ejemplos, para ello es importante tener en cuenta la versión de Python que estás utilizando.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python 3.5 a 3.8:&lt;/strong&gt; Es necesario importar los tipos de la librería &lt;code&gt;typing&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;List&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Set&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Tuple&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Dict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;l&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;List&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;s&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Set&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {&lt;span style="color:#98c379"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;t&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Tuple&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;Python&amp;#34;&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;d&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Dict&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {&lt;span style="color:#98c379"&gt;&amp;#34;active&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;False&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python 3.9 y posteriores:&lt;/strong&gt; Puedes utilizar la sintaxis estándar sin importar &lt;code&gt;typing&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;l&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;list&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;s&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;set&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {&lt;span style="color:#98c379"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;t&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;tuple&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;Python&amp;#34;&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;d&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;dict&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {&lt;span style="color:#98c379"&gt;&amp;#34;active&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;False&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En los ejemplos anteriores podemos observar que estamos definiendo un tipo de colección diferente por cada varibale y cabe destacar que en el caso de las colecciones podemos definir el tipo de dato que va a contener cada una de las variables, debes tener en cuenta que:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;para &lt;code&gt;list&lt;/code&gt; y &lt;code&gt;set&lt;/code&gt; se utiliza el tipo de dato que va a contener entre corchetes &lt;code&gt;[]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;para &lt;code&gt;tuple&lt;/code&gt; se define el tipo de dato y la posición dentro de la tupla entre corchetes &lt;code&gt;[]&lt;/code&gt;, es decir que en el ejemplo se espera que sea una tupla de tres elementos que estaran en el siguiente orden &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;para &lt;code&gt;dict&lt;/code&gt; se define el tipo de dato que va a contener la llave y el valor entre corchetes &lt;code&gt;[]&lt;/code&gt;, es decir que en el ejemplo se espera que sea un diccionario con llaves de tipo &lt;code&gt;str&lt;/code&gt; y valores de tipo &lt;code&gt;bool&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="combinación-de-tipos-en-python"&gt;Combinación de Tipos en Python&lt;/h2&gt;
&lt;p&gt;En algunos casos, es necesario que las variables puedan contener más de un tipo de dato o incluso que puedan ser opcionales. Para ello se han definido diversas estrategias para alcanzar esta funcionalidad&lt;/p&gt;
&lt;h3 id="definir-más-de-un-tipo"&gt;Definir Más de un Tipo&lt;/h3&gt;
&lt;p&gt;Utiliza el carácter &lt;code&gt;|&lt;/code&gt; para definir más de un tipo de dato en una variable, este carácter actúa como un &lt;code&gt;OR&lt;/code&gt; lógico:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;one&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Para versiones anteriores a Python 3.9, importa &lt;code&gt;Union&lt;/code&gt; de &lt;code&gt;typing&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Union&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Union&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Union&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;one&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="valores-opcionales-o-none"&gt;Valores Opcionales o &lt;code&gt;None&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Para definir que un valor es opcional, añade &lt;code&gt;None&lt;/code&gt; como parte de los tipos posibles:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Para versiones anteriores a Python 3.9, utiliza &lt;code&gt;Optional&lt;/code&gt; o &lt;code&gt;Union&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# Opción 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Optional&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# Opción 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Union&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Union&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="definir-valores-fijos"&gt;Definir Valores Fijos&lt;/h3&gt;
&lt;p&gt;Si deseas restringir los valores que puede tomar una variable, usa &lt;code&gt;Literal&lt;/code&gt; de &lt;code&gt;typing&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Literal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;cards&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Literal&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;clubs&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;diamonds&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;hearts&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;spades&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;cards&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;clubs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="definir-tipos-personalizados"&gt;Definir Tipos Personalizados&lt;/h2&gt;
&lt;p&gt;EN Python asi como con las variables es posible definir tipos personalizados, para simplificar la lectura del código o incluso para darle un mejor entendimiento al código. en la siguiente pieza de código podemos ver esta funcionalidad.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Literal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;UserType&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Literal&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ID&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;PersonalData&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;dict&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;float&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;tuple&lt;/span&gt;[&lt;span style="color:#e06c75"&gt;ID&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;PersonalData&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;UserType&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;UserUgly&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;tuple&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;dict&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;float&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;], &lt;span style="color:#e06c75"&gt;Literal&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Como podemos observa en el ejemplo anterior estamos separando nuestra definición de tipos en otros tipos para facilitar la lectura de nuestro código, en el caso de &lt;code&gt;User&lt;/code&gt; y &lt;code&gt;UserUgly&lt;/code&gt; estamos definiendo un tipo de dato que va a ser una tupla que va a contener un &lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;PersonalData&lt;/code&gt; y &lt;code&gt;UserType&lt;/code&gt; y en el caso de &lt;code&gt;UserUgly&lt;/code&gt; estamos definiendo el mismo tipo de dato pero de una manera menos legible.&lt;/p&gt;
&lt;p&gt;si escribieramos el mismo código para versiones anteriores a Python 3.9, el código se vería de la siguiente manera:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Literal&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Union&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;UserType&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Literal&lt;/span&gt;[&lt;span style="color:#98c379"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ID&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Union&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;PersonalData&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;dict&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Optional&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;bool&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;float&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;tuple&lt;/span&gt;[&lt;span style="color:#e06c75"&gt;ID&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;PersonalData&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;UserType&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="datos-io-en-python"&gt;Datos IO en Python&lt;/h2&gt;
&lt;p&gt;Cuando trabajes con datos de entrada/salida, como la lectura de archivos, usa el tipo &lt;code&gt;IO&lt;/code&gt; de &lt;code&gt;typing&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;IO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;text_file&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;IO&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# text, json, xml, html...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;bin_file&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;IO&lt;/span&gt;[&lt;span style="color:#e5c07b"&gt;bytes&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# jpeg, png, pdf, mp3...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El tipo &lt;code&gt;IO&lt;/code&gt; es un tipo genérico que se utiliza para representar objetos que son streams de entrada o salida, como archivos y sockets, y solo admite tipos de datos &lt;code&gt;str&lt;/code&gt; y &lt;code&gt;bytes&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;En este artículo, hemos cubierto las nociones básicas sobre cómo agregar tipos a tus variables en Python. En el próximo artículo, exploraremos cómo agregar tipos a funciones.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/tipado-funciones" class="btn btn-outline-primary " rel="" &gt;Tipado de funciones&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</content:encoded></item><item><title>Tipado en Python: Introducción</title><link>https://blog.dacadev.com/python/tipado/introduccion/</link><pubDate>Fri, 09 Aug 2024 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/tipado/introduccion/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Descubre por qué el tipado en Python es clave para proyectos profesionales. Aprende sobre errores de lógica, validación de tipos y cómo mejorar la calidad de tu código.</description><media:content url="https://blog.dacadev.com/images/python/typing/introduction/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#por-qué-es-importante-el-tipado"&gt;¿Por qué es importante el tipado?&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#tipos-de-errores"&gt;Tipos de errores&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;Este artículo hace parte de una serie que explicará el tipado en Python, a continuación puedes ver la recopilación de todos los posts de la serie.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/serie-de-tipado" class="btn btn-outline-primary " rel="" &gt;Ver serie&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="por-qué-es-importante-el-tipado"&gt;¿Por qué es importante el tipado?&lt;/h2&gt;
&lt;p&gt;Antes de ahondar en el uso de tipos en python, debemos hacer un pequeño énfasis de porque nace la necesidad de implementar &lt;em&gt;“tipado”&lt;/em&gt; y análisis estático de código en Python&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Escribo tipado entre comillas porque realmente no implementamos tipado en python, sino que simulamos tener tipos en Python, esto lo veremos vas adelante, pero es importante tenerlo en cuenta.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Python, al ser un lenguaje &lt;strong&gt;interpretado&lt;/strong&gt;, significa que el código es leído y ejecutado solamente cuando el interprete pasa por la línea de código, por lo que el error, si existe, solo aparecerá cuando ejecutamos dicha línea de código. Por el contrario en un lenguaje compilado como Go o Java, el código debe primero construido (compilado) y después usado, pero es en el proceso de compilación en donde se realizan validaciones de tipos dentro del código y estas validaciones permiten capturar errores tempranos.&lt;/p&gt;
&lt;h3 id="tipos-de-errores"&gt;Tipos de errores&lt;/h3&gt;
&lt;p&gt;En este punto vale la pena agrupar los errores en dos grupos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Errores de excepción: Son errores que se generan cuando un programa falla al ejecutar una acción determinada, como por ejemplo abrir un archivo que no existe.&lt;/li&gt;
&lt;li&gt;Errores de lógica: Son errores que no generan excepción sino que generan un resultado errado al esperado.&lt;/li&gt;
&lt;/ul&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Los errores de lógica son los mas peligrosos ya que al no levantar una excepción normalmente permiten que el flujo de trabajo continue con los errores.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;p&gt;En ese orden de ideas nos centraremos en los errores de &lt;strong&gt;lógica&lt;/strong&gt; ya que son los errores que podemos &lt;em&gt;&amp;ldquo;capturar&amp;rdquo;&lt;/em&gt; gracias a los tipos, por ejemplo con ayuda de tipos podemos capturar errores tempranos como:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;validar el uso de los tipos de datos dentro de nuestro código, por ejemplo si estamos usando un string en un lugar donde deberíamos de usar un entero&lt;/li&gt;
&lt;li&gt;validar que los métodos que estamos llamando existan en el objeto que estamos usando&lt;/li&gt;
&lt;li&gt;validar que los atributos que estamos usando en un objeto existan&lt;/li&gt;
&lt;li&gt;validar que los argumentos que estamos pasando a una función sean los correctos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Veamos la forma tradicional de validar y capturar errores de tipos en Python. Para ello debemos de implementar una serie sentencias en nuestro código para asegurarnos que estamos usando los tipos correctos. esto puede afectar la legibilidad del código y la productividad, e incluso el rendimiento de nuestros programas en algunos casos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;clean_text&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;assert&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;), &lt;span style="color:#98c379"&gt;&amp;#34;Input must be a string&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;# process a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;calculate_sum&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;nums&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;sum&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;num&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;nums&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;not&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;num&lt;/span&gt;, (&lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;float&lt;/span&gt;)):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;raise&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ValueError&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Input must be a number&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;sum&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;sum&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En el caso de &lt;code&gt;clean_text&lt;/code&gt; estamos validando que el argumento &lt;code&gt;a&lt;/code&gt; sea un &lt;code&gt;string&lt;/code&gt;, en caso de que no sea un &lt;code&gt;string&lt;/code&gt;, levantamos una excepción. En el caso de &lt;code&gt;calculate_sum&lt;/code&gt; estamos validando que los argumentos que estamos pasando sean &lt;code&gt;int&lt;/code&gt; o &lt;code&gt;float&lt;/code&gt;, en caso de que no sea alguno de estos, levantamos una excepción.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;En el caso &lt;code&gt;clean_text&lt;/code&gt; estamos usando &lt;code&gt;assert&lt;/code&gt; para validar el tipo de dato, sin embargo &lt;code&gt;assert&lt;/code&gt; no es recomendado para validar tipos de datos, ya que se puede desactivar en tiempo de ejecución, por lo que no es una buena práctica usarlo como captura de errores en código, sin embargo es probable que lo encuentres en tu día a día como desarrollador.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Si miramos a profundidad el código no esta mal, sino que estamos agregando lógica adicional que esta afectando la legibilidad del código, y un de los principales objetivos que tenemos como programadores es escribir código limpio y legible. para los demás o tu yo del futuro. Imagina si hicieramos esto en códigos mas complejos y extensos.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;p&gt;La siguiente entrega de esta seria aborda el tema de como implementar tipado en Python, y como podemos mejorar la legibilidad del código y la productividad.
para verla da click en el siguiente botón.
&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.dacadev.com/python/tipado/tipado-basico" class="btn btn-outline-primary " rel="" &gt;Tipado básico en Python&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</content:encoded></item><item><title>Tipado en Python: Serie de DacaDev</title><link>https://blog.dacadev.com/python/tipado/serie-de-tipado/</link><pubDate>Thu, 08 Aug 2024 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/tipado/serie-de-tipado/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Descubre cómo el tipado en Python mejora la calidad de tu código, facilita la detección de errores y potencia la escalabilidad de tus proyectos de software. Explora nuestra serie de artículos en DacaDev.</description><media:content url="https://blog.dacadev.com/images/python/typing/serie/banner.png" medium="image" type="image/png"/><content:encoded>&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt;, al ser un lenguaje interpretado y dinámicamente tipado, no incluye de forma nativa la gestión y manejo de tipos. Esta característica es extremadamente útil y práctica, especialmente para quienes están comenzando en el mundo del desarrollo de software.&lt;/p&gt;
&lt;p&gt;Sin embargo, a medida que los proyectos crecen, esta ventaja inicial puede convertirse en un desafío. La ausencia de un sistema de tipos explícito puede complicar la lectura del código, dificultar la depuración de errores y limitar la escalabilidad del proyecto.&lt;/p&gt;
&lt;p&gt;Por esta razón, ha surgido la iniciativa de implementar tipado en &lt;strong&gt;Python&lt;/strong&gt;. Con esta herramienta, los desarrolladores pueden tener un mayor control sobre los tipos de datos en su código, lo que permite capturar errores tempranos y mejorar la calidad del software desde las primeras etapas del desarrollo.&lt;/p&gt;
&lt;p&gt;En &lt;em&gt;DacaDev&lt;/em&gt;, hemos creado una serie de artículos que explican de manera detallada el tipado en &lt;strong&gt;Python&lt;/strong&gt;. A continuación, puedes acceder a cada uno de los artículos de la serie:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.dacadev.com/python/tipado/introduccion"



 


&gt;Introducción al tipado en Python (teoría)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.dacadev.com/python/tipado/tipado-basico"



 


&gt;Tipado básico en Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.dacadev.com/python/tipado/tipado-funciones"



 


&gt;Tipado de funciones en Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.dacadev.com/python/tipado/tipado-clases"



 


&gt;Tipado de clases en Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.dacadev.com/python/tipado/estructuras-de-datos"



 


&gt;Estructuras de datos tipadas en Python&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>Colecciones en Python: namedtuple()</title><link>https://blog.dacadev.com/python/colecciones/namedtuples/</link><pubDate>Tue, 14 May 2024 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/colecciones/namedtuples/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Descubre cómo namedtuple() del módulo collections en Python optimiza el manejo de estructuras de datos con ejemplos prácticos. Aprende a mejorar la legibilidad y eficiencia de tu código con namedtuple().</description><media:content url="https://blog.dacadev.com/images/programming/python/collections/namedtuples/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-es-namedtuple"&gt;¿Qué es &lt;code&gt;namedtuple()&lt;/code&gt;?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#ejemplos-de-uso"&gt;Ejemplos de uso&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#crear-una-namedtuple"&gt;Crear una &lt;code&gt;namedtuple&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#crear-una-namedtuple-con-valores-por-defecto"&gt;Crear una &lt;code&gt;namedtuple&lt;/code&gt; con valores por defecto&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#controlar-el-renombramiento-de-los-campos"&gt;Controlar el renombramiento de los campos&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#las-namedtuples-son-clases"&gt;Las &lt;code&gt;namedtuples&lt;/code&gt; son Clases&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#por-qué-usar-namedtuples"&gt;¿Por qué usar &lt;code&gt;namedtuples&lt;/code&gt;?&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;En este artículo, conocerás la función &lt;code&gt;namedtuple&lt;/code&gt; del módulo &lt;code&gt;collections&lt;/code&gt; de la biblioteca estándar de &lt;strong&gt;Python&lt;/strong&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="qué-es-namedtuple"&gt;¿Qué es &lt;code&gt;namedtuple()&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;namedtuple()&lt;/code&gt; es una función que retorna una nueva clase, la cual permite acceder a los valores de una tupla tanto por índice como a través de un nombre definido al crear la tupla.&lt;/p&gt;
&lt;p&gt;Primero, examinaremos la firma de la función para entender cómo funciona y, posteriormente, analizaremos por qué y cuándo es beneficioso usarla.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;namedtuple&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;typename&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;field_names&lt;/span&gt;, &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;rename&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;False&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;defaults&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;module&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Esta firma revela cinco argumentos importantes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;typename&lt;/code&gt;: el nombre que se asignará a la nueva clase creada.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;field_names&lt;/code&gt;: ya sea un string o un iterable de strings que representan los nombres de los campos de la tupla. El orden de estos strings determina cómo se accederán los valores.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rename&lt;/code&gt;: un valor booleano que, si se activa, permite que la función reemplace nombres duplicados o conflictivos automáticamente.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defaults&lt;/code&gt;: permite definir valores predeterminados para los campos de la tupla, asignando valores desde el final hacia el inicio de la lista de campos.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;module&lt;/code&gt;: un string que asocia la nueva tupla a un módulo específico.&lt;/li&gt;
&lt;/ul&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Los argumentos definidos después de &lt;code&gt;*&lt;/code&gt; son argumentos que deben pasarse como &lt;code&gt;keyword arguments&lt;/code&gt; (es decir, como &lt;code&gt;nombre=valor&lt;/code&gt;), no de manera posicional.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="ejemplos-de-uso"&gt;Ejemplos de uso&lt;/h2&gt;
&lt;h3 id="crear-una-namedtuple"&gt;Crear una &lt;code&gt;namedtuple&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Primero, veamos cómo crear una nueva tupla sencilla:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;Coordinates&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Coordinates&amp;#34;&lt;/span&gt;, [&lt;span style="color:#98c379"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;y&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;z&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Coordinates&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;x:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;y:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;y&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;z:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;z&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;x:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt;[&lt;span style="color:#d19a66"&gt;0&lt;/span&gt;], &lt;span style="color:#98c379"&gt;&amp;#39;y:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt;[&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;], &lt;span style="color:#98c379"&gt;&amp;#39;z:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt;[&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El resultado de este código será:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ python main.py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Coordinates&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;1, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;2, &lt;span style="color:#e06c75"&gt;z&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;3&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x: &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; y: &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; z: &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x: &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; y: &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; z: &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Como observamos, creamos una nueva clase llamada &lt;code&gt;Coordinates&lt;/code&gt; con campos &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, y &lt;code&gt;z&lt;/code&gt;. Luego instanciamos &lt;code&gt;point_1&lt;/code&gt; y accedimos a sus valores tanto por nombre como por índice.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Al declarar &lt;code&gt;point_1&lt;/code&gt;, los valores se asignan en el mismo orden en que se especifican en la tupla: primero &lt;code&gt;x&lt;/code&gt;, después &lt;code&gt;y&lt;/code&gt;, y finalmente &lt;code&gt;z&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="crear-una-namedtuple-con-valores-por-defecto"&gt;Crear una &lt;code&gt;namedtuple&lt;/code&gt; con valores por defecto&lt;/h3&gt;
&lt;p&gt;Definiendo valores por defecto, que deben ser iterables, podemos especificar los valores que se asignarán a los campos si no se proporcionan al crear la instancia:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;UserData&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;UserData&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#98c379"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;age&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;country&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;defaults&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;example@mail.com&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;CO&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;david&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserData&lt;/span&gt;( &lt;span style="color:#98c379"&gt;&amp;#34;David&amp;#34;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;28&lt;/span&gt;, )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;juan&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserData&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Juan&amp;#34;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;24&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;juan@mail.com&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;david&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;juan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El resultado de este código será:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;UserData&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;28, &lt;span style="color:#e06c75"&gt;email&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;example@mail.com&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;country&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;CO&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;UserData&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Juan&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;24, &lt;span style="color:#e06c75"&gt;email&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;juan@mail.com&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;country&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;CO&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Los valores por defecto se asignan de derecha a izquierda a los campos que no tienen valores asignados al crear la instancia.&lt;/p&gt;
&lt;p&gt;Pero debemos de tener en cuenta que si no pasamos todos los argumentos que no están definidos por defecto, la función lanzará un error.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;unknown&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserData&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;unknown&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Traceback &lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;most recent call last&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#98c379"&gt;&amp;#34;/home/dacacode/dacadev/personal-blog/tempCodeRunnerFile.python&amp;#34;&lt;/span&gt;, line 9, in &amp;lt;module&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;unknown&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; UserData&lt;span style="color:#56b6c2"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ^^^^^^^^^^
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TypeError: UserData.__new__&lt;span style="color:#56b6c2"&gt;()&lt;/span&gt; missing &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; required positional arguments: &lt;span style="color:#98c379"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; and &lt;span style="color:#98c379"&gt;&amp;#39;age&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="controlar-el-renombramiento-de-los-campos"&gt;Controlar el renombramiento de los campos&lt;/h3&gt;
&lt;p&gt;Activando el argumento &lt;code&gt;rename&lt;/code&gt; como &lt;code&gt;True&lt;/code&gt;, la función automáticamente renombra campos duplicados o que sean palabras reservadas del lenguaje. Primero vamos a crear una tupla normal con nombres de campos que pueden entrar en conflicto.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;dynamic_fields&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;def&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;arg&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;EspecialInfo&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;EspecialInfo&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;dynamic_fields&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;EspecialInfo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al ejecutar el código vas a obtener un error como el siguiente:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Traceback &lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;most recent call last&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#98c379"&gt;&amp;#34;/home/dacacode/dacadev/personal-blog/tempCodeRunnerFile.python&amp;#34;&lt;/span&gt;, line 4, in &amp;lt;module&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;EspecialInfo&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; namedtuple&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;EspecialInfo&amp;#34;&lt;/span&gt;, dynamic_fields&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#98c379"&gt;&amp;#34;/home/dacacode/.pyenv/versions/3.11.5/lib/python3.11/collections/__init__.py&amp;#34;&lt;/span&gt;, line 398, in namedtuple
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; raise ValueError&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Type names and field names cannot be a &amp;#39;&lt;/span&gt;..&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ValueError: Type names and field names cannot be a keyword: &lt;span style="color:#98c379"&gt;&amp;#39;def&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pero si habilitamos la opcion de &lt;code&gt;rename&lt;/code&gt; el código funcionará, ya que la función se encarga de procesar esos casos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;dynamic_fields&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;def&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;arg&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;EspecialInfoV2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;EspecialInfoV2&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;dynamic_fields&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;rename&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;EspecialInfoV2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;data&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;EspecialInfoV2&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;print&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;Hello, World!&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ahora si obtendremos un resultado positivo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;class &lt;span style="color:#98c379"&gt;&amp;#39;__main__.EspecialInfoV2&amp;#39;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EspecialInfoV2&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;_1&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;print&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;arg&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Hello, World!&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;_3&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En donde podemos ver que los atributos que son &lt;code&gt;keywords&lt;/code&gt; y &lt;code&gt;duplicados&lt;/code&gt; han sido renombrados por valores posicionales, en este caso &lt;code&gt;_1&lt;/code&gt; y &lt;code&gt;_3&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="las-namedtuples-son-clases"&gt;Las &lt;code&gt;namedtuples&lt;/code&gt; son Clases&lt;/h2&gt;
&lt;p&gt;Por último, pero no menos importante, recuerda que el resultado de la función &lt;code&gt;namedtuple&lt;/code&gt; es una clase que hereda de &lt;code&gt;tuple&lt;/code&gt;, lo que significa que podemos usarla como cualquier otra clase. Por ejemplo, podemos usar la nueva clase como padre de otra para extender su funcionalidad:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;Coordinates&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Coordinates&amp;#34;&lt;/span&gt;, [&lt;span style="color:#98c379"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;y&amp;#34;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;z&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Point&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;Coordinates&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__add__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Point&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;x&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;y&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;y&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;z&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;z&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Point&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;point_2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Point&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;6&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;point_2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;point_1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;point_2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El resultado de este código será:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Point&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;1, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;2, &lt;span style="color:#e06c75"&gt;z&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;3&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Point&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;4, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;5, &lt;span style="color:#e06c75"&gt;z&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;6&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Point&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;5, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;7, &lt;span style="color:#e06c75"&gt;z&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;9&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="por-qué-usar-namedtuples"&gt;¿Por qué usar &lt;code&gt;namedtuples&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;Una de las principales razones para usar las &lt;code&gt;namedtuple&lt;/code&gt; es la mejora de la legibilidad del código, ya que al momento los atributos para acceder a sus elementos es más fácil de entender que si lo hacemos por índice.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;UserInfo&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;namedtuple&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;UserInfo&amp;#39;&lt;/span&gt;, [&lt;span style="color:#98c379"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;age&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;email&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# Mejora la legibilidad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserInfo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;28&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;mail@mail.com&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# David&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;age&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# 30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;email&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# mail@mail.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# Debes tener en tu mente el orden de los campos, no es lo ideal!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;userRaw&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {&lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;28&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;mail@mail.com&amp;#39;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;[&lt;span style="color:#d19a66"&gt;0&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# David&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;[&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# 30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;[&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# mail@mail.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Otros beneficios que encontramos es en la eficiencia del código, ya que al utilizar &lt;strong&gt;tuplas&lt;/strong&gt; (o &lt;code&gt;nametuples&lt;/code&gt;) encontramos que:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Las &lt;strong&gt;tuplas&lt;/strong&gt; tienen mayor rendimiento al momento de ser creadas, debido a que son objetos inmutables y su alocación en memoria es mucho ams eficiente que las clasicas lsitas o diccionarios.&lt;/li&gt;
&lt;li&gt;Son ideales para procesar información que debe mantenerse constante durante todo su tiempo de vida, ya que las tuplas son inmutables.&lt;/li&gt;
&lt;li&gt;El tiempo de acceso a los elementos de la tupla es más rápido que las listas o los diccionarios.&lt;/li&gt;
&lt;/ul&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Esto no significa que las &lt;strong&gt;tuplas&lt;/strong&gt; sean mejores que otras estructuras de datos, esto depende de cada caso en particular y debes analizarlo antes de tomar una decisión.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;





 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Para más información sobre &lt;code&gt;namedtuple&lt;/code&gt;, visita la documentación oficial en este &lt;a href="https://docs.python.org/3/library/collections.html#collections.namedtuple"




 target="_blank"
 


&gt;&lt;strong&gt;enlace&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</content:encoded></item></channel></rss>