<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-family:georgia,serif;font-size:large"></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">El mar, 5 ene 2021 a las 16:19, Jesus Cea (<<a href="mailto:jcea@jcea.es">jcea@jcea.es</a>>) escribió:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 4/1/21 11:18, Chema Cortes wrote:<br>
> La recursividad en python es muy limitada. Pero lo que viene a descubrir <br>
> es algo que se podría haber hecho mejor con generadores. En cuanto al <br>
> otro uso, sería una aplicación parcial de argumentos (functools.partial).<br>
> <br>
> Aún así, hay algoritmos recursivos que no son tan fácilmente <br>
> transcribibles en iterables.<br>
<br>
Más allá del uso chorras para convertir una función concreta de <br>
recursiva a iterativa, para mí lo interesante del artículo es el uso de <br>
"closures" para generar funciones personalizadas que se llevan su estado <br>
consigo. No todo necesita el coste de crear clases e instancias <br>
explícitas, no todo se puede solucionar con generadores y <br>
"functools.partial()" no proporciona estado mutable.<br>
<br>
El uso de "closures" explícitos me parece algo que vale la pena añadir a <br>
la caja de herramientas, siempre vigilando que no existe una forma más <br>
elegante de hacer algo concreto.<br>
<br></blockquote><div><br></div><div><div style="font-family:georgia,serif;font-size:large" class="gmail_default">Aunque suene bien que las funciones mantengan su propio estado, nunca es aconsejable que las funciones tengan efectos colaterales (violación de la <a href="https://en.wikipedia.org/wiki/Referential_transparency">transparencia referencial</a>).<br></div><br></div><div></div><div><div style="font-family:georgia,serif;font-size:large" class="gmail_default">Las clausuras son importantes y están en el fondo de muchos recursos como pueden ser los <i>decoradores</i>. Pero es siempre posible crear un generador (<span style="font-family:monospace">Iterable</span>) en lugar de una función con clausura (<span style="font-family:monospace">Callable</span>). La diferencia es que los generadores  están <i>protocolizados</i>,  con opciones para poner fin a la iteración (<span style="font-family:monospace">StopIteration</span>), para inyectar datos a la clausura (método <span style="font-family:monospace">.send()</span>) o para destruir el generador (<span style="font-family:monospace">GeneratorExit</span>). También se pueden usar en gran parte de la librería estándar, con las funciones de itertools como las más potentes.<br></div><div style="font-family:georgia,serif;font-size:large" class="gmail_default"><br></div><div style="font-family:georgia,serif;font-size:large" class="gmail_default">Por comparar,  la función de fibonacci como generador:</div><div style="font-size:large" class="gmail_default"><span style="font-family:monospace"><br></span></div><div class="gmail_default"><font size="2"><span style="font-family:monospace">from itertools import islice</span></font></div><div class="gmail_default"><font size="2"><span style="font-family:monospace"><br></span></font></div><div class="gmail_default"><font size="2"><span style="font-family:monospace">def fib():</span></font></div><div class="gmail_default"><font size="2"><span style="font-family:monospace">    a, b = 1, 1</span></font></div><div class="gmail_default"><font size="2"><span style="font-family:monospace">    while True:</span></font></div><div class="gmail_default"><font size="2"><span style="font-family:monospace">        yield a</span></font></div><div style="font-family:georgia,serif" class="gmail_default"><font size="2"><span style="font-family:monospace">        a, b = b, a+b</span><br></font></div></div><div><font size="2"><span style="font-family:monospace"></span></font></div><span class="gmail_default" style="font-family:georgia,serif;font-size:large"></span><pre class="gmail-mw gmail-mx gmail-my gmail-mz gmail-na gmail-nc gmail-nd gmail-ne"><font size="2"><span id="gmail-7ce0" class="gmail-in gmail-nf gmail-mb gmail-hq gmail-ng gmail-b gmail-dm gmail-nh gmail-ni gmail-s gmail-nj">def fib_<span class="gmail_default">generator</span>(n):<br>    <span class="gmail_default">return next(islice(fib(), n-1, None))</span></span></font></pre></div><div class="gmail_quote"><br></div><div class="gmail_quote"><div style="font-family:georgia,serif;font-size:large" class="gmail_default">Si se compara, es casi el doble de rápida que la que viene en el artículo, <span style="font-family:monospace">fib_closure</span>.</div><div style="font-family:georgia,serif;font-size:large" class="gmail_default"><br></div></div><div class="gmail_quote"><div style="font-family:georgia,serif;font-size:large" class="gmail_default">Saludos.</div><br><div><span style="font-family:georgia,serif"> </span></div></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div>Hyperreals *R  "Quarks, bits y otras criaturas infinitesimales": <a href="https://blog.ch3m4.org" target="_blank">https://blog.ch3m4.org</a><br>Buscador Python Hispano: <a href="https://blog.ch3m4.org/pages/busqueda-python-es/" target="_blank">http://busca.ch3m4.org</a></div></div></div></div></div></div>