<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Johnnatan Sandoval Cardona</title>
    <description>The latest articles on Forem by Johnnatan Sandoval Cardona (@johnnatan_sandovalcardon).</description>
    <link>https://forem.com/johnnatan_sandovalcardon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2017085%2F679d5c1b-bf2a-4e95-9810-27ada6a8dbb4.png</url>
      <title>Forem: Johnnatan Sandoval Cardona</title>
      <link>https://forem.com/johnnatan_sandovalcardon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/johnnatan_sandovalcardon"/>
    <language>en</language>
    <item>
      <title>Algo más de azúcar para python</title>
      <dc:creator>Johnnatan Sandoval Cardona</dc:creator>
      <pubDate>Tue, 29 Oct 2024 15:34:23 +0000</pubDate>
      <link>https://forem.com/johnnatan_sandovalcardon/algo-mas-de-azucar-para-python-2g1g</link>
      <guid>https://forem.com/johnnatan_sandovalcardon/algo-mas-de-azucar-para-python-2g1g</guid>
      <description>&lt;p&gt;Python 3.12 introdujo algo de azúcar sintáctica para definir clases y funciones genéricas. Veamos cómo funciona:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__getitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se agradece esta simplificación que es útil en definiciones simples.&lt;/p&gt;

&lt;p&gt;También es ahora permitido crear aliases con &lt;code&gt;type&lt;/code&gt;, aunque aún no he tenido la oportunidad de usarlo. El proyecto en el que trabajo en este momento usa python 3.10.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
      <category>typehinting</category>
      <category>syntacticsugar</category>
    </item>
    <item>
      <title>Eligiendo la versión por defecto de node con nvm</title>
      <dc:creator>Johnnatan Sandoval Cardona</dc:creator>
      <pubDate>Mon, 28 Oct 2024 21:25:09 +0000</pubDate>
      <link>https://forem.com/johnnatan_sandovalcardon/eligiendo-la-version-por-defecto-de-node-con-nvm-39p6</link>
      <guid>https://forem.com/johnnatan_sandovalcardon/eligiendo-la-version-por-defecto-de-node-con-nvm-39p6</guid>
      <description>&lt;p&gt;Para manejar las diferentes versiones de &lt;code&gt;node&lt;/code&gt; uso &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;&lt;code&gt;nvm&lt;/code&gt;&lt;/a&gt;. Al abrir una nueva terminal, la versión instalada se reinicia, lo que me obliga a ejecutar &lt;code&gt;nvm use &amp;lt;version&amp;gt;&lt;/code&gt; continuamente.&lt;/p&gt;

&lt;p&gt;Para definir una versión por defecto, podemos ejecutar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm alias default v18.16.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esa forma, toda nueva terminal tendrá por defecto, la versión elegida.&lt;/p&gt;

</description>
      <category>node</category>
      <category>nvm</category>
    </item>
    <item>
      <title>La dificultad de las revisiones de código</title>
      <dc:creator>Johnnatan Sandoval Cardona</dc:creator>
      <pubDate>Sat, 26 Oct 2024 16:30:58 +0000</pubDate>
      <link>https://forem.com/johnnatan_sandovalcardon/la-dificultad-de-las-revisiones-de-codigo-4dff</link>
      <guid>https://forem.com/johnnatan_sandovalcardon/la-dificultad-de-las-revisiones-de-codigo-4dff</guid>
      <description>&lt;p&gt;Las revisiones de código son difíciles. No obstante, en la mayoría de empresas en las que he estado, no se hacen bien.&lt;/p&gt;

&lt;p&gt;¿Qué dificultad posee una revisión de código? Que no es simplemente un problema técnico. Implica relaciones entre seres humanos. Por lo que he visto, algunos temen "herir" susceptibilidades al hacer un comentario, o se sienten mal frente a ciertas críticas al código. Claro está, hay maneras de decir las cosas; no obstante, deberíamos intentar ver las revisiones como un esfuerzo colectivo por mejorar, no como algo personal.&lt;/p&gt;

&lt;p&gt;En varias empresas he visto que se sacrifica la calidad por no hacer sentir mal a los otros. Y eso también hace que las revisiones sean superficiales. La persona que revisa no piensa realmente el código; solo da una mirada general.&lt;/p&gt;

&lt;p&gt;Por otro lado, está el problema de los estilos de programar. Como individuos, y siendo la programación una cuestión creativa, en parte, hay estilos. ¿Cómo separar lo que es realmente una necesidad, de una preferencia personal? Las diferencias en gustos y en experiencia hace difícil la comunicación al realizar una revisión de código. Por ejemplo: ¿abstraer o no abstraer? Me encuentro muchas veces con sugerencias de abstracciones que, desde mi punto de vista, son innecesarias. Soy más de abstraer cuando he logrado captar la esencia del problema. Para ello, necesito más de un caso. Prefiero dejar pasar algunos casos no generalizados, y no hacer una abstracción apresurada. No obstante, alguien con más experiencia, tanto en programar, como en conocimiento de un código, puede ver patrones que uno no puede ver. Tal vez tenga razón en sugerir un patrón (aunque, también, podría equivocarse porque, aceptémoslo, todos nos equivocamos).&lt;/p&gt;

&lt;p&gt;En mi actual empresa, me he encontrado con revisiones de código bastante estrictas. En ocasiones, tienen razón con una sugerencia, en otras, no estoy seguro de si tenga sentido, o si de verdad sea una razón para bloquear la aprobación. Lo cierto es que tardo entre una y dos semanas en que mi código se apruebe, teniendo en cuenta que quienes revisan hacen una revisión diaria, en promedio. Siento que estoy yendo demasiado despacio. Sé que llevo apenas unos pocos meses, y he tenido que lidiar con cinco bases de código de servicios diferentes, y con personas diferentes, sin tener conocimiento profundo de cada uno, ni de las interacciones entre ellos. Más me gustaría acelerar todo. Reducir la probabilidad de recibir comentarios. &lt;/p&gt;

&lt;p&gt;Con esto último, pasa que programamos pensando en el comentario que hará el otro, así no estemos totalmente de acuerdo con él. Haré esto así porque no quiero que me retrasen el código. ¿Es esto correcto? Es difícil. Las revisiones de código resultan ser un problema muy humano y no meramente técnico, como nos gustaría.&lt;/p&gt;

</description>
      <category>programación</category>
      <category>revisionesdecódigo</category>
    </item>
    <item>
      <title>El módulo decimal de python</title>
      <dc:creator>Johnnatan Sandoval Cardona</dc:creator>
      <pubDate>Wed, 25 Sep 2024 21:42:21 +0000</pubDate>
      <link>https://forem.com/johnnatan_sandovalcardon/el-modulo-decimal-de-python-5e8j</link>
      <guid>https://forem.com/johnnatan_sandovalcardon/el-modulo-decimal-de-python-5e8j</guid>
      <description>&lt;p&gt;Los lenguajes de programación tienen diversos tipos de datos para manejar información numérica. El tipo entero (&lt;code&gt;int&lt;/code&gt;), real (&lt;code&gt;float&lt;/code&gt;) y python soporta otros como fracciones y complejos.&lt;/p&gt;

&lt;p&gt;Hoy, sin embargo, quiero hablar del tipo &lt;code&gt;decimal&lt;/code&gt;. Los &lt;code&gt;float&lt;/code&gt; o de coma flotante, tiene varios problemas de precisión que no pueden tolerarse en ciertos tipos de aplicaciones como, por ejemplo, las que tienen que ver con finanzas.&lt;/p&gt;

&lt;p&gt;Veamos un caso muy simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;

&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.999999999999999999&lt;/span&gt;  &lt;span class="c1"&gt;# True
&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.999999999999999999&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# False
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extendiendo sobre la clase &lt;code&gt;decimal&lt;/code&gt;, existe el módulo &lt;a href="https://github.com/vimeo/py-money" rel="noopener noreferrer"&gt;&lt;code&gt;py-money&lt;/code&gt;&lt;/a&gt; que adiciona a los números una moneda como &lt;code&gt;USD&lt;/code&gt; o &lt;code&gt;COP&lt;/code&gt;, permitiendo a las aplicaciones que así lo requieren, tener una precisión tan alta como se quiera.&lt;/p&gt;

&lt;p&gt;Claro está que no es posible tener una precisión infinita en una computadora. Sin embargo, el módulo &lt;code&gt;decimal&lt;/code&gt; se puede ajustar a una precisión tan grande como se necesite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getcontext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;prec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# outpus 28 by default
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usé bastante el módulo &lt;code&gt;decimal&lt;/code&gt; y también la librería &lt;code&gt;py-money&lt;/code&gt; en un momento en que trabajaba en una aplicación financiera. Es correctamente soportada por &lt;code&gt;django&lt;/code&gt; y otros frameworks.&lt;/p&gt;

</description>
      <category>python</category>
      <category>decimal</category>
      <category>finanzas</category>
    </item>
    <item>
      <title>Conociendo uv</title>
      <dc:creator>Johnnatan Sandoval Cardona</dc:creator>
      <pubDate>Mon, 23 Sep 2024 01:40:11 +0000</pubDate>
      <link>https://forem.com/johnnatan_sandovalcardon/conociendo-uv-1717</link>
      <guid>https://forem.com/johnnatan_sandovalcardon/conociendo-uv-1717</guid>
      <description>&lt;p&gt;&lt;code&gt;uv&lt;/code&gt; es el nuevo administrador de proyectos escrito en Rust para python. ¿Por qué una nueva alternativa, habiendo tantas disponibles? Hace mucho empecé a usar &lt;code&gt;pipenv&lt;/code&gt;, el cual eventualmente se volvió inútil. Luego migré a &lt;code&gt;poetry&lt;/code&gt; que, además, usa mi empresa actual. Es una mejora, más no me termina de convencer.&lt;/p&gt;

&lt;p&gt;Y es que no hay una solución definitiva en python a lo que quiere lograr &lt;code&gt;uv&lt;/code&gt;. Un &lt;code&gt;cargo&lt;/code&gt; para python.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;poetry&lt;/code&gt; no es un reemplazo de &lt;code&gt;pypenv&lt;/code&gt;. Por lo tanto, hay que seguir usando otras herramientas. Además, no es transparente.&lt;/p&gt;

&lt;p&gt;He empezado a experimentar con &lt;code&gt;uv&lt;/code&gt; y puedo decir que ya puedo reemplazar, cuando menos, &lt;code&gt;pyenv&lt;/code&gt;. Tal vez podría usarlo en lugar de &lt;code&gt;poetry&lt;/code&gt;; no obstante, en mi actual empresa usamos &lt;code&gt;poetry&lt;/code&gt; y no creo que estemos listos para una migración.&lt;/p&gt;

&lt;p&gt;¿Por qué creo que es una mejora? Con &lt;code&gt;uv&lt;/code&gt; puedo ejecutar &lt;code&gt;uv run mi-script.py&lt;/code&gt; y de manera automática utiliza un entorno virtual. No solo eso, puedo instalar paquetes para el archivo que son manejados dentro de comentarios. Por ejemplo: &lt;code&gt;uv run --with rich example.py&lt;/code&gt;. Las dependencias y el entorno virtual se maneja de manera transparente.&lt;/p&gt;

&lt;p&gt;No está de más decir que es extremadamente rápido. Muy por encima de las opciones. No por nada está hecho en rust lo que, a su vez, ofrece otra ventaja: no dependemos de una instalación previa de python, que puede ser problemática. &lt;code&gt;uv&lt;/code&gt; es un binario que se instala y funciona sin problemas.&lt;/p&gt;

&lt;p&gt;Empezaré a usarlo para manejar proyectos cada vez que pueda y como reemplazo de &lt;code&gt;pip&lt;/code&gt; por lo que espero seguir escribiendo al respecto.&lt;/p&gt;

&lt;p&gt;¿Desventajas? He visto comentarios que hablan de desconfianza hacia &lt;code&gt;astral&lt;/code&gt;, la empresa detrás de &lt;code&gt;uv&lt;/code&gt; y de cómo se financiarán. Igualmente, no les agrada del todo que se construya en &lt;code&gt;rust&lt;/code&gt; y no en &lt;code&gt;python&lt;/code&gt;, lo que puede ser una dificultad. Yo, por mi parte, pienso que no son razones suficientes. Por un lado, la comunidad ha sido incapaz de entregar una solución totalmente satisfactoria. Por el otro, es software libre, y, en caso de algún movimiento no deseado por parte de &lt;code&gt;astral&lt;/code&gt;, se puede crear una bifurcación, aún si el costo de mantenimiento, en principio, es mayor por ser otro lenguaje.&lt;/p&gt;

</description>
      <category>uv</category>
      <category>python</category>
      <category>poetry</category>
      <category>pipenv</category>
    </item>
    <item>
      <title>Explorando org-babel en emacs</title>
      <dc:creator>Johnnatan Sandoval Cardona</dc:creator>
      <pubDate>Sun, 15 Sep 2024 20:18:44 +0000</pubDate>
      <link>https://forem.com/johnnatan_sandovalcardon/explorando-org-babel-en-emacs-4ak0</link>
      <guid>https://forem.com/johnnatan_sandovalcardon/explorando-org-babel-en-emacs-4ak0</guid>
      <description>&lt;p&gt;Soy usuario de &lt;code&gt;GNU/Emacs&lt;/code&gt; desde el año 2005. A pesar de tanto tiempo, no me considero un experto. No me he querido meter de&lt;br&gt;
lleno con &lt;code&gt;ELisp&lt;/code&gt;, por ejemplo, así que las configuraciones que hago a &lt;code&gt;emacs&lt;/code&gt;, las hago basándome en consejos de internet. Y, de un tiempo para acá, empecé a usar &lt;code&gt;doom emacs&lt;/code&gt;, que me entrega una &lt;em&gt;"distribución&lt;/em&gt;" pre-configurada y lista para usarse.&lt;/p&gt;

&lt;p&gt;No obstante, cada tanto pruebo nuevas características que, aunque las&lt;br&gt;
conozco desde hace mucho tiempo, no me había animado a usarlas. Una de&lt;br&gt;
las más recientes es &lt;code&gt;org-babel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;org-mode&lt;/code&gt; me permite introducir bloques de código por aquí y por allá. Es una forma de programación literata. Para ello, puedo definir bloques que empiezan con &lt;code&gt;begin_src&lt;/code&gt; y terminan con &lt;code&gt;end_src&lt;/code&gt;. Cualquier modo que emacs soporte, lo puedo definir de la siguiente&lt;br&gt;
manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#+begin_src python
print("Hola mundo")
#+end_src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Al exportar, puedo obtener coloreado de sintaxis del lenguaje. No obstante, hay algo más que puedo hacer y es ejecutar el bloque de código con &lt;code&gt;C-c C-c&lt;/code&gt;. Y lo puedo hacer con cualesquier lenguaje que org soporte, siempre que tenga acceso al intérprete.&lt;/p&gt;

&lt;p&gt;Algo que he hecho en los últimos días, es almacenar instrucciones de la línea de comandos para pruebas que hago:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#+begin_src sh :results output&amp;gt;
http get https://google.com
#+end_src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esa forma, puedo repetir continuamente un comando haciendo pequeñas modificaciones y ver la salida en el mismo buffer de emacs. Me gusta porque no soy muy fan de &lt;code&gt;postman&lt;/code&gt;, y de esta forma no lo necesito. Puedo usar &lt;code&gt;httpie&lt;/code&gt; o &lt;code&gt;curl&lt;/code&gt;, donde me siento más cómodo.&lt;/p&gt;

&lt;p&gt;Veamos el resultado de lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#+begin_src sh :results output
curl google.com
#+end_src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;: &lt;span class="nt"&gt;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"content-type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"text/html;charset=utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
: &lt;span class="nt"&gt;&amp;lt;TITLE&amp;gt;&lt;/span&gt;301 Moved&lt;span class="nt"&gt;&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY&amp;gt;&lt;/span&gt;
: &lt;span class="nt"&gt;&amp;lt;H1&amp;gt;&lt;/span&gt;301 Moved&lt;span class="nt"&gt;&amp;lt;/H1&amp;gt;&lt;/span&gt;
: The document has moved
: &lt;span class="nt"&gt;&amp;lt;A&lt;/span&gt; &lt;span class="na"&gt;HREF=&lt;/span&gt;&lt;span class="s"&gt;"http://www.google.com/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;here&lt;span class="nt"&gt;&amp;lt;/A&amp;gt;&lt;/span&gt;.
: &lt;span class="nt"&gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Puedo copiar, puedo pegar o hacer lo que quiera. En este momento, no he probado la posibilidad de comunicar un bloque con otro, o de manejar sesiones. Tal vez lo haga más adelante. Por ahora, este es un paso más en emacs que me gusta.&lt;/p&gt;

</description>
      <category>emacs</category>
      <category>babel</category>
      <category>org</category>
      <category>programaciónliterata</category>
    </item>
    <item>
      <title>Consideraciones en los serializadores del DRF</title>
      <dc:creator>Johnnatan Sandoval Cardona</dc:creator>
      <pubDate>Thu, 05 Sep 2024 14:36:48 +0000</pubDate>
      <link>https://forem.com/johnnatan_sandovalcardon/consideraciones-en-los-serializadores-del-drf-1816</link>
      <guid>https://forem.com/johnnatan_sandovalcardon/consideraciones-en-los-serializadores-del-drf-1816</guid>
      <description>&lt;p&gt;&lt;code&gt;Django&lt;/code&gt;{.verbatim} es un gran &lt;em&gt;framework&lt;/em&gt; para desarrollo web en&lt;br&gt;
python. El &lt;code&gt;django rest framework&lt;/code&gt;{.verbatim}, lo especializa para crear APIs &lt;code&gt;REST&lt;/code&gt;{.verbatim} con mucha facilidad.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Django&lt;/code&gt;{.verbatim} tiene clases como &lt;code&gt;modelo&lt;/code&gt;{.verbatim} y &lt;code&gt;vista&lt;/code&gt;{.verbatim}, que corresponden, no de manera exacta, con los correspondientes del patrón modelo-vista-controlador.&lt;sup id="fnref1"&gt;1&lt;/sup&gt; El DRF agrega una clase nueva, los serializadores, encargados de transformar desde una representación, como json, a objetos de python y viceversa. Los serializadores son bastante flexibles y permiten incrustar en ellos lógica compleja de validación y de transformación de datos. No obstante, hacerlo es una mala idea, ya que podemos terminar con serializadores que implementan parte de la lógica del negocio o del dominio.&lt;/p&gt;

&lt;p&gt;Este artículo no pretende hablar de ese problema, sino de otro que puede surgir con el abuso de los serializadores. Supongamos que tenemos una modelo llamado &lt;code&gt;Company&lt;/code&gt; en nuestra aplicación. Los campos de este modelo/tabla poco nos importan. A su vez, tenemos varias vistas que deben lidiar con \"compañías\". Aparte de las típicas acciones de crear, listar, actualizar, traer o eliminar, otras clases podrían tener que lidiar de alguna forma con la clase compañía. Por ejemplo, por conveniencia, podríamos querer incrustar en los datos de un usuario, su compañía:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Joseph"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por tanto, crearemos uno o varios serializadores para lidiar con el&lt;br&gt;
modelo &lt;code&gt;Company&lt;/code&gt;. Es un patrón que he visto en varios proyectos el crear una clase padre llamada, por ejemplo, &lt;code&gt;CompanySerializer&lt;/code&gt;, y de allí se desprenden clases específicas como &lt;code&gt;CompanyUpdateSerializer&lt;/code&gt; o &lt;code&gt;CompanyCreateSerializer&lt;/code&gt; en un intento de usar la herencia para&lt;br&gt;
compartir funcionalidad aparentemente común.&lt;/p&gt;

&lt;p&gt;No solo eso. Es muy probable que la vista de usuario que entrega la&lt;br&gt;
compañía incrustada, decida compartir el mismo &lt;code&gt;CompanySerializer&lt;/code&gt; en un intento de seguir el malentendido principio de &lt;em&gt;no te repitas&lt;/em&gt;, o&lt;br&gt;
&lt;em&gt;Don\'t Repeat Yourself (DRY)&lt;/em&gt;. Voy a justificar por qué esto es una&lt;br&gt;
mala idea por varias razones.&lt;/p&gt;

&lt;p&gt;Comencemos por argumentar en contra de la herencia. Existe otro&lt;br&gt;
principio de diseño que nos sugiere preferir la composición por sobre la herencia. Es demasiado fácil y tentador abusar de la herencia como mecanismo de reutilización de código, lo que puede resultar en una aplicación mucho más difícil de entender. Lo explícito es mejor que lo implícito, y pocas cosas hay más implícitas que la herencia. Mi experiencia con el &lt;code&gt;DRF&lt;/code&gt;{.verbatim} no ha hecho más que reafirmar en mi ese principio. Aunque parece intuitivo el que hayan diversos tipos de serializadores, lo cierto es que terminan siendo usados en contextos muy distintos. Especialmente cuando la aplicación crece, nos encontraremos con que habrá más lógica de negocio necesaria para crear, actualizar, e incluso para listar. Esa lógica es incompatible entre si, y termina siendo necesario hacer comprobaciones para saber en qué contexto se está llamando el serializador.&lt;/p&gt;

&lt;p&gt;Dicho de otro modo, estamos violando el principio de única responsabilidad que dice que solo debe haber un motivo para que una clase cambie. Cuando una serializador es compartido en contextos tan diferentes, tiene múltiples razones para cambiar. Lo que sucede en un contexto, o caso de uso, puede afectar a otros contextos.&lt;/p&gt;

&lt;p&gt;Desde otro punto de vista, nos damos cuenta que la clase &lt;code&gt;CompanySerializer&lt;/code&gt; es referenciada por muchas otras clases en contextos diferentes. Eso es otra señal de un problema de diseño. Cuando de una clase dependen muchas otras (en términos visuales, a una clase entran muchas líneas), un cambio en esta puede afectar a sus dependientes.&lt;/p&gt;

&lt;p&gt;Y es que no tiene sentido compartir serializadores. La apariencia de&lt;br&gt;
reutilizar no es más que eso; algo superficial.&lt;/p&gt;

&lt;p&gt;Pensemos en que la vista de usuario que incrusta la compañía, aunque en apariencia accede a la misma fila de la base de datos, puede tener menos (o más) permisos que las demás vistas que también la usan. Quiero decir que puede necesitar retornar menos campos por cuestión de privacidad y seguridad. ¿Cómo manejamos esto con un serializador compartido? Se vuelve complejo y es proponso a errores. Por ejemplo, una nueva característica puede querer acceder a una compañía con un dato que se considera privado en otros contextos. Lo agrega al serializador y, por arte de magia, ahora es accesible en todas las vistas que dependen de él. Esto, claro está, tiene solución, pero facilita demasiado el equivocarse.&lt;/p&gt;

&lt;p&gt;¿Cuál es la solución? Simple, no reutilizar serializadores. Podemos&lt;br&gt;
también decir: a cada vista le corresponde un único serializador. No importa que accedan al mismo dato, en apariencia. El contexto tan diferente hace que no sea, en el fondo, lo mismo.&lt;/p&gt;

&lt;p&gt;Dado que es una relación única, podemos usar una estrategia de ubicar un serializador al interior de su vista. Así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CompanyView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;  &lt;span class="c1"&gt;# Podemos acceder al serializador haciendo: self.Serialzer
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es una opción, por supuesto, aunque es ideal para situaciones simples. ¿Qué pasa cuando el serializador posee serializadores anidados? Tal vez se haga complejo. Se puede resolver, pero, cuando menos, podemos siempre recurrir a la relación uno a uno ubicando los serializadores en el archivo &lt;code&gt;serializer.py&lt;/code&gt; como es costumbre.&lt;/p&gt;

&lt;h1&gt;
  
  
  Notas
&lt;/h1&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;En django, una vista no corresponde con el concepto de &lt;em&gt;vista&lt;/em&gt; en MVC. La combinación entre una plantilla (template) y una vista de    django corresponde de mejor manera con la V de MVC. ¿Y los controladores? No hay tal cosa en django. Por esta razón se promueve la idea de vistas delgadas y modelos obesos. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>django</category>
      <category>djangorestframework</category>
      <category>serializadores</category>
      <category>design</category>
    </item>
    <item>
      <title>Descubriendo itertools</title>
      <dc:creator>Johnnatan Sandoval Cardona</dc:creator>
      <pubDate>Tue, 03 Sep 2024 02:07:05 +0000</pubDate>
      <link>https://forem.com/johnnatan_sandovalcardon/descubriendo-itertools-507j</link>
      <guid>https://forem.com/johnnatan_sandovalcardon/descubriendo-itertools-507j</guid>
      <description>&lt;p&gt;&lt;code&gt;Itertools&lt;/code&gt; es una de las librerías más interesantes de python. Contiene una serie de funciones inspiradas en lenguajes funcionales que sirven para trabajar con iteradores.&lt;/p&gt;

&lt;p&gt;En este artículo mencionaré alguna de las que más me han llamado la atención y que vale la pena tener presentes para no reinventar la rueda cada vez.&lt;/p&gt;

&lt;h1&gt;
  
  
  Count
&lt;/h1&gt;

&lt;p&gt;Varias veces he implementado un conteo infinito (bueno, que termina&lt;br&gt;
explícitamente en algún momento con un &lt;code&gt;break&lt;/code&gt;) usando un ciclo &lt;code&gt;while True&lt;/code&gt;. &lt;code&gt;itertools&lt;/code&gt; nos ofrece una mejor alternativa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    2
    4
    6
    8
    10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como puede verse en el ejemplo, de no ser por el &lt;code&gt;break&lt;/code&gt;, &lt;code&gt;count&lt;/code&gt; retornaría infinitos números. El código anterior es más o menos equivalente a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    2
    4
    6
    8
    10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  batched
&lt;/h1&gt;

&lt;p&gt;Una función para realizar algo muy común: obtener datos de una secuencia en lotes de tamaño &lt;code&gt;n&lt;/code&gt;. Veamos un ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;batched&lt;/span&gt;

    &lt;span class="n"&gt;sequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;batched&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  &lt;span class="c1"&gt;# lotes de tamaño 2
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    (1, 2)
    (3, 4)
    (5, 6)
    (7,)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es de notar que el último lote puede ser de un tamaño menor o igual a &lt;code&gt;n&lt;/code&gt;, como en este caso. Bastante útil, ¿no creen?&lt;/p&gt;

&lt;h1&gt;
  
  
  pairwise
&lt;/h1&gt;

&lt;p&gt;Otra función sencilla y útil. Dada una secuencia (en realidad, dado un iterador), nos entrega sus elementos en pares.&lt;/p&gt;

&lt;p&gt;Veámoslo mejor con un ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pairwise&lt;/span&gt;

    &lt;span class="n"&gt;sequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;pairwise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    1 2
    2 3
    3 4
    4 5
    5 6
    6 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La cantidad de parejas es una menos que el tamaño de la secuencia de entrada.&lt;/p&gt;

&lt;h1&gt;
  
  
  product
&lt;/h1&gt;

&lt;p&gt;Finalmente, para esta corta entrada, quiero hablar de &lt;code&gt;product&lt;/code&gt;, una&lt;br&gt;
implementación del producto cartesiano.&lt;/p&gt;

&lt;p&gt;Útil para reemplazar un &lt;code&gt;for&lt;/code&gt; anidado que recorra dos secuencia de datos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;

    &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   1 5
    1 6
    1 7
    2 5
    2 6
    2 7
    3 5
    3 6
    3 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recibe un parámetro que nos permite realizar el producto cartesiano de una&lt;br&gt;
secuencia consigo misma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;

    &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a3&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    1 1 1
    1 1 2
    1 1 3
    1 2 1
    1 2 2
    1 2 3
    1 3 1
    1 3 2
    1 3 3
    2 1 1
    2 1 2
    2 1 3
    2 2 1
    2 2 2
    2 2 3
    2 3 1
    2 3 2
    2 3 3
    3 1 1
    3 1 2
    3 1 3
    3 2 1
    3 2 2
    3 2 3
    3 3 1
    3 3 2
    3 3 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En una próxima entrada, mencionaré otras funciones más de este útil módulo de&lt;br&gt;
librería estándar de python. Espero les sea de utilidad.&lt;/p&gt;

</description>
      <category>python</category>
      <category>itertools</category>
      <category>iteradores</category>
    </item>
  </channel>
</rss>
