4 potentes funciones que aún le faltan a Python

Python es un lenguaje vivo, en constante desarrollo para mantenerse al día. Python Software Foundation no solo está haciendo adiciones a la biblioteca estándar y a la implementación de referencia CPython, sino que también está introduciendo nuevas características y refinamientos en el lenguaje en sí.

Por ejemplo, Python 3.8 introdujo una nueva sintaxis para asignaciones en línea (el "operador de morsa") que hace que ciertas operaciones sean más concisas. Otra mejora de sintaxis recientemente aprobada, la coincidencia de patrones, facilitará la escritura de código que evalúe uno de los muchos casos posibles. Ambas características se inspiraron en su presencia y utilidad en otros idiomas.

Y son solo dos de una gran cantidad de funciones útiles que podrían agregarse a Python para hacer que el lenguaje sea más expresivo, más poderoso y más adecuado para el mundo de la programación moderna. ¿Qué más podríamos desear? Aquí hay cuatro características más del lenguaje que podrían agregar algo de valor real a Python: dos podríamos obtener y dos probablemente no. 

Verdaderas constantes

Python realmente no tiene el concepto de valor constante. Hoy, las constantes en Python son principalmente una cuestión de convención. El uso de un nombre en mayúsculas y mayúsculas, por ejemplo, DO_NOT_RESTART es una pista de que la variable está destinada a ser una constante. De manera similar, la  typing.Final anotación de tipo proporciona una sugerencia a los linters de que un objeto no debe modificarse, pero no lo impone en tiempo de ejecución.

¿Por qué? Porque la mutabilidad está profundamente arraigada en los comportamientos de Python. Cuando asigna un valor a una variable, por ejemplo,  x=3 está creando un nombre en el espacio de nombres local  x, y apuntándolo a un objeto en el sistema que tiene el valor entero  3. Python asume en todo momento que los nombres son mutables, que cualquier nombre podría apuntar a cualquier objeto. Eso significa que cada vez que se usa un nombre, Python se toma la molestia de buscar a qué objeto apunta. Este dinamismo es una de las principales razones por las que Python se ejecuta más lentamente que otros lenguajes. El dinamismo de Python ofrece una gran flexibilidad y comodidad, pero a costa del rendimiento en tiempo de ejecución.

Una ventaja de tener declaraciones constantes verdaderas en Python sería cierta reducción en la frecuencia de las búsquedas de objetos que tienen lugar durante el tiempo de ejecución y, por lo tanto, un mejor rendimiento. Si el tiempo de ejecución sabe de antemano que un valor dado nunca cambia, no tiene que buscar sus enlaces. Esto también podría proporcionar una vía para otras optimizaciones de terceros, como sistemas que generan código nativo de la máquina a partir de aplicaciones de Python (Cython, Nuitka).

Sin embargo, las constantes verdaderas serían un cambio importante y, muy probablemente, un cambio incompatible hacia atrás. También sería objeto de debate si las constantes vendrían a través de una nueva sintaxis, por ejemplo, el $ símbolo aún no utilizado  , o como una extensión de la forma existente de Python para declarar nombres. Finalmente, está la cuestión filosófica más amplia de si las constantes verdaderas tienen sentido o no en un lenguaje donde el dinamismo ha sido una gran parte del atractivo.

En resumen, es posible que veamos constantes verdaderas en Python, pero sería un cambio importante.

Verdadera sobrecarga y genéricos

En muchos idiomas, se pueden escribir varias versiones de la misma función para que funcionen con diferentes tipos de entrada. Por ejemplo, una  to_string() función podría tener diferentes implementaciones para convertir enteros, números en coma flotante u otros objetos, pero compartirían el mismo nombre por conveniencia. La "sobrecarga" o "genéricos" facilitan la escritura de software robusto, ya que puede escribir métodos genéricos para procesos comunes en lugar de utilizar un método específicamente para un tipo determinado.

Python le permite usar un nombre de función para hacer el trabajo de muchos, pero no al definir múltiples instancias de una función. Puede definir un nombre solo una vez en un ámbito determinado y vincularlo a un solo objeto a la vez, por lo que no puede tener varias versiones de una sola función con el mismo nombre.

Lo que los desarrolladores de Python suelen hacer para solucionar este problema es utilizar elementos integrados como  isinstance() o  type() para determinar el tipo de variable enviada a una función y, a continuación, actuar en función del tipo. A veces, esto implica el envío a una versión específica de tipo de una función bajo el capó. Pero este enfoque hace que sea difícil para otros desarrolladores extender su función a menos que se esfuerce por hacerla extensible, por ejemplo, enviando métodos dentro de una clase, que podrían ser subclasificados.

PEP 3124, avanzado en abril de 2007, propuso un mecanismo para decorar funciones para indicar que podrían estar sobrecargadas. La propuesta se pospuso en lugar de ser rechazada por completo, lo que significa que la idea era fundamentalmente sólida, pero no era el momento adecuado para implementarla. Un factor que podría acelerar la adopción de la sobrecarga en Python, o hacer que la idea se descarte por completo, es la implementación del sistema de coincidencia de patrones recientemente propuesto.

En teoría, la coincidencia de patrones podría usarse debajo del capó para manejar el despacho de sobrecarga. Sin embargo, la coincidencia de patrones también podría darse como una razón para no implementar genéricos en Python, ya que ya proporciona una forma elegante de distribuir operaciones basadas en firmas de tipos.

Por lo tanto, algún día podríamos tener una verdadera sobrecarga en Python, o sus ventajas podrían ser reemplazadas por otros mecanismos.

Optimizaciones de recursividad de cola

Muchos compiladores de lenguaje emplean optimizaciones de recursividad de cola, donde las funciones que se llaman a sí mismas no crean nuevos marcos de pila en la aplicación y, por lo tanto, corren el riesgo de hacer explotar la pila si se ejecutan durante demasiado tiempo. Python no hace esto y, de hecho, sus creadores se han opuesto constantemente a hacerlo.

Una razón es que gran parte de Python, de adentro hacia afuera, usa  iteración en  lugar de  recursividad  : generadores, corrutinas, etc. En este caso, significa usar una función con un bucle y una estructura de pila en lugar de un mecanismo recursivo. Cada llamada del bucle se puede guardar en una pila para crear una nueva recursividad y salir de la pila cuando finaliza la recursividad.

Se anima a los desarrolladores de Python a utilizar estos patrones en lugar de la recursividad, por lo que parece haber pocas esperanzas de optimizaciones de recursividad. Las posibilidades aquí no son del todo probables, ya que los modismos de Python apoyan otras soluciones.

Lambdas multilínea

Lambdas, o funciones anónimas, llegaron a Python solo después de cierta resistencia por parte del creador del lenguaje Guido van Rossum. Como las lambdas de Python existen ahora, están muy restringidas: solo le permiten usar una sola expresión (esencialmente, cualquier cosa a la derecha de un signo igual en una operación de asignación) como el cuerpo de la función. Si desea un bloque completo de declaraciones, simplemente divídalas y cree una función real a partir de ellas.

La razón se reduce al diseño del lenguaje tal como lo ve Van Rossum. Como escribió van Rossum en 2006, “Encuentro   inaceptable cualquier solución que incruste un bloque basado en sangría en medio de una expresión. Dado que encuentro una sintaxis alternativa para la agrupación de declaraciones (por ejemplo, llaves o palabras clave de inicio / fin) igualmente inaceptable, esto hace que una lambda multilínea sea un rompecabezas sin solución ".

En otras palabras, el problema no es técnico, sino la falta de una sintaxis para lambdas multilínea que complemente la estética existente de la sintaxis de Python. Probablemente no haya forma de hacerlo que no implique la creación de un caso especial, y un lenguaje que acumula casos especiales tiende a resultar desagradable de usar. Hasta que aparezca un unicornio así, tendremos que conformarnos con funciones definidas por separado.

Es probable que las lambdas multilínea no estén ocurriendo en Python.

Leer más sobre Python:

  • Python 3.9: novedades y mejoras
  • Las mejores características nuevas en Python 3.8
  • Mejor gestión de proyectos de Python con Poetry
  • Virtualenv y venv: explicación de los entornos virtuales de Python
  • Python virtualenv y venv qué hacer y qué no hacer
  • Explicación de subprocesos y subprocesos de Python
  • Cómo usar el depurador de Python
  • Cómo usar timeit para perfilar el código Python
  • Cómo usar cProfile para perfilar el código Python
  • Comience con async en Python
  • Cómo usar asyncio en Python
  • Cómo convertir Python a JavaScript (y viceversa)
  • Python 2 EOL: Cómo sobrevivir al final de Python 2
  • 12 pitones para cada necesidad de programación
  • 24 bibliotecas de Python para cada desarrollador de Python
  • 7 dulces IDE de Python que quizás te hayas perdido
  • 3 deficiencias principales de Python y sus soluciones
  • 13 marcos web de Python comparados
  • 4 marcos de prueba de Python para acabar con sus errores
  • 6 fantásticas funciones nuevas de Python que no querrá perderse
  • 5 distribuciones de Python para dominar el aprendizaje automático
  • 8 fantásticas bibliotecas de Python para el procesamiento del lenguaje natural
  • 6 bibliotecas de Python para procesamiento paralelo
  • ¿Qué es PyPy? Python más rápido sin dolor
  • ¿Qué es Cython? Python a la velocidad de C