[PyVigo] [Py-MAD] [Py-ES] Don’t Use Recursion In Python Any More,Python Closure — A Pythonic technique you must know

Francisco José Fernández Naranjo fjfnaranjo en gmail.com
Mar Ene 12 15:56:58 CET 2021


Sobre lo que comentas al principio Chema, y sobre lo que dice Guido,
siempre me resultó curioso una cosa a la que pocas veces se hace
referencia cuando se habla de este tema.

Tendemos a hablar de ciertas capacidades del lenguaje como si fueran
aspiracionales. Por ejemplo, a pensar que usar programación funcional
(o las opciones pseudo-funcionales) es "mejor" (o más pythónico) para
ciertos casos. Y tendemos por tanto a decidir que cuando alguien no
usa una característica del lenguaje el problema es de comprensión de
la característica en sí por su parte (cuando no eres directamente
condescendiente y piensas que es un inútil). Pero yo lo que me
encuentro en mi día a día cuando trabajo es un mundo donde la gente
tiene unas habilidades muy diversas y donde no quieres que todo el
mundo sea una persona extremadamente capaz en muchas cosas, si no
donde quieres un grupo de personas que se complementen.

Concretando, bajar al nivel de la programación funcional, sobre todo
si no se comprende bien de manera no-funcional, va a agregar
complejidad al código o el diseño que va a repercutir en la capacidad
de otras personas para leerlo, comentarlo, mantenerlo... Esto aplica
también a conocimientos específicos, como por ejemplo, operar correcta
y eficientemente con datos usando cython, o entender como llevar un
proceso muy complejo a una librería en C para usarla desde Python a
más alto nivel.

Cuando yo me encuentro con esto, siempre me ha gustado mucho el
programador que sabe escribir esa complejidad en la parte más profunda
del diseño, y deja las operaciones más universales en la parte
superior del mismo. Eso permite simultáneamente combinar la capacidad
específica de ese programador con los compañeros que no han
desarrollado tanto en ese área.

Una de las cosas que comentas al final, cuando dices "hay mucho
potencial en python que no se usa bien o se ignora que está ahí" (y
donde solapas un poco con la opinión de Guido) deja un poco fuera la
decisión de ese programador pragmático que saber medir muy bien donde
poner su aprendizaje y esfuerzo para cumplir simultáneamente con el
"Simple is better than complex" y con el "Complex is better than
complicated". Creo que dos figuras en la comunidad de Python que
representan un poco esta diferencia de apreciación por lo pragmático
son Guido y Raymond Hettinger. Donde ves por una lado el programador
que aspira a la belleza en lo "complex" y el que aspira a la belleza
en lo "simple".

Y en ese caso, creo que es muy acertado la decisión que hasta ahora se
ha tomado en el diseño de Python de que algunas características tienen
mejor lugar en paquetes como "functools". Formando parte como dices de
ese compendio de buenas ideas de otros lenguajes. Y esa "pena" que ves
al final, se puede ver también como una de las grandes fortalezas del
lenguaje.

Un saludo,
Naranjo.




On Tue, Jan 12, 2021 at 2:56 PM Chema Cortés <pych3m4 en gmail.com> wrote:
>
> Hola, José Luis:
>
> Guido suele decir que las características funcionales de python se usan muy poco porque no se llegan a entender. Ese fue el motivo, al menos, para que la función reduce dejara  de estar en builtins y acabara en el módulo functools.
>
> El cálculo lambda de Church sí que está relacionado con la transparencia referencial, pero no dice nada de clausuras. La idea es que mediante "aplicaciones" y "reducciones" transformes una expresión lambda hasta llegar a un valor, independientemente del orden en que hagas las transformaciones.
>
> Si una misma expresión lambda, ante el mismo argumento da resultados distintos, entonces el orden en que hagas su evaluación cambia el resultado. Estaría incumpliendo el principio de transparencia referencial.
>
> Si se encapsula una función con una clausura para mantener estados, los resultados de la función podrían ser distintos ante los mismos argumentos. No podemos sustituir la llamada a la función por su resultado, por lo que se incumple la transparencia referencial. En realidad, solemos decir más que la función tiene "efectos colaterales".
>
> En haskell, no existen los "contextos" como los llamas. Todo son "transformaciones" entre unos valores de entrada y de salida. Para mantener "estados" se usan las "transformaciones monádicas", que no son "clausuras". No se almacena ningún estado, sólo indicas de qué estado a qué estado pasas, sin ninguna persistencia entre llamadas.
>
> En cuanto a las características de programación funcional que pueda tener python, muy pocos las usan o son conscientes de que las usan. Python, junto con su librería estándar, es un compendio de conocimientos aplicados que han sido traídos desde otros lenguajes. Mucho de lo que llamamos "modo pythónico" de hacer las cosas no son otra cosa que transformaciones funcionales con una teoría detrás que ignoramos mayormente: compresiones de listas, tipos algebraicos, dataclases, ordenación por clave, etc, etc.En mi opinión, hay mucho potencial en python que no se usa bien o se ignora que está ahí.
>
> Seguro que Guido hace bien en mantener un lenguaje python accesible para todos y que no quiera liarla más con conceptos de programación funcional. Pero me parece una pena.
>
>
> Saludos.
>
>
>
> El lun, 11 ene 2021 a las 21:18, Jose Luis (<jleahred en gmail.com>) escribió:
>>
>> Una pequeña observación.
>>
>> Güido ha explicado de forma brillante y coherente en alguna ocasión, que Python no es ni pretende ser "muy" funcional
>>
>> Los "closures" de Python (hay que matizar, porque cada uno define closure como le da la gana), capturan "cosas" (llámalo estado si quieres), OK
>> Pero eso no va en contra de la transparencia referencial.
>>
>> Las lambdas de Haskell capturan "cosas" y es muy raro que rompan la transparencia referencial.
>>
>> De hecho, el concepto closure diría que viene del cálculo lambda (del genial "profe" de Turing, Alonzo Church), y simplificando, son funciones anónimas (aka lambdas) que capturan y tampoco rompen la transparencia referencial (es la gracia del cálculo lambda vs la máquina de Turing ;-)
>>
>> Una función lambda con un contexto difernte, es una función diferente. Si tú le pones el mismo nombre "mutando" o haces mutaciones del contexto... puedes romper la transparencia referencial, pero no es por el concepto de "closure" o captura
>> Vamos, que si capturar "cosas" (aka contexto, aka estado, aka variables, aka "llámalo como quieras") violara la transparencia referencial, Haskell no sería muy funcional (ni el cálculo lambda)  ;-)
>>
>> Reitero que no tengo claro que forzar "mucho" la programación funcional en Python sea buena idea.
>> Que yo lo opine, poco valor tiene, pero considero a Güido como un tipo coherente y muy inteligente, del que he aprendido un montón de cosas con sus reflexiones y explicaciones; y corregidme si me equivoco, pero diría que Güido no es partidario de "forzar" python con programación funcional (si fuera un tipo más serio y simpático, mandaría los enlaces de Güido al respecto, pero los tengo que buscar, estoy cansado y tampoco dispongo de tiempo en este momento)
>>
>>
>> Saludos de un humilde amante de la programación funcional (amor no correspondido; ni me quiere la programación funcional, ni la imperativa, pero sigo dando guerra ;-)
>>
>> On Wed, Jan 6, 2021 at 5:31 PM Chema Cortes <pych3m4 en gmail.com> wrote:
>>>
>>>
>>> El mar, 5 ene 2021 a las 16:19, Jesus Cea (<jcea en jcea.es>) escribió:
>>>>
>>>> On 4/1/21 11:18, Chema Cortes wrote:
>>>> > La recursividad en python es muy limitada. Pero lo que viene a descubrir
>>>> > es algo que se podría haber hecho mejor con generadores. En cuanto al
>>>> > otro uso, sería una aplicación parcial de argumentos (functools.partial).
>>>> >
>>>> > Aún así, hay algoritmos recursivos que no son tan fácilmente
>>>> > transcribibles en iterables.
>>>>
>>>> Más allá del uso chorras para convertir una función concreta de
>>>> recursiva a iterativa, para mí lo interesante del artículo es el uso de
>>>> "closures" para generar funciones personalizadas que se llevan su estado
>>>> consigo. No todo necesita el coste de crear clases e instancias
>>>> explícitas, no todo se puede solucionar con generadores y
>>>> "functools.partial()" no proporciona estado mutable.
>>>>
>>>> El uso de "closures" explícitos me parece algo que vale la pena añadir a
>>>> la caja de herramientas, siempre vigilando que no existe una forma más
>>>> elegante de hacer algo concreto.
>>>>
>>>
>>> Aunque suene bien que las funciones mantengan su propio estado, nunca es aconsejable que las funciones tengan efectos colaterales (violación de la transparencia referencial).
>>>
>>> Las clausuras son importantes y están en el fondo de muchos recursos como pueden ser los decoradores. Pero es siempre posible crear un generador (Iterable) en lugar de una función con clausura (Callable). La diferencia es que los generadores están protocolizados,  con opciones para poner fin a la iteración (StopIteration), para inyectar datos a la clausura (método .send()) o para destruir el generador (GeneratorExit). También se pueden usar en gran parte de la librería estándar, con las funciones de itertools como las más potentes.
>>>
>>> Por comparar, la función de fibonacci como generador:
>>>
>>> from itertools import islice
>>>
>>> def fib():
>>>     a, b = 1, 1
>>>     while True:
>>>         yield a
>>>         a, b = b, a+b
>>>
>>> def fib_generator(n):
>>>     return next(islice(fib(), n-1, None))
>>>
>>>
>>> Si se compara, es casi el doble de rápida que la que viene en el artículo, fib_closure.
>>>
>>> Saludos.
>>>
>>>
>>> --
>>> Hyperreals *R  "Quarks, bits y otras criaturas infinitesimales": https://blog.ch3m4.org
>>> Buscador Python Hispano: http://busca.ch3m4.org
>>> _______________________________________________
>>> Asociación Python España: http://www.es.python.org/
>>> Python Madrid: http://www.python-madrid.es/
>>> Madrid mailing list
>>> Madrid en lists.es.python.org
>>> https://lists.es.python.org/listinfo/madrid
>
> _______________________________________________
> Asociación Python España: http://www.es.python.org/
> Python Madrid: http://www.python-madrid.es/
> Madrid mailing list
> Madrid en lists.es.python.org
> https://lists.es.python.org/listinfo/madrid


Más información sobre la lista de distribución Vigo