Dinamismo en Python

La característica que quiero destacar en este documento es la gran ventaja de Python sobre los lenguajes de programación no dinámicos. Al no tener que declarar las variables, no las estamos limitando a la utilización en la que estaba pensando el programador. Como ejemplo, tenemos el caso del clásico juego de la vida. Se da el caso de que alguien (siento no dar referencias más concretas, pero todo esto apareció en usenet hace un par de años) hizo un mini-juego de la vida, con sus leyes de supervivencia, etc. Como respuesta al mensaje de usenet, otro programador envió una generalización a tres dimensiones del juego original, algo en lo que el primer autor ni siquiera había pensado. Esto fue posible porque cada vez que el autor decía, por ejemplo, distancia(a,b) no hacía ninguna suposición sobre los objetos a y b. Él pensaba que hablaba de puntos 2D, pero no le fue necesario hacerlo explícito en ningún momento, por lo que las reglas que construía eran generales. Desde luego, si el efecto es buscado, se le da más potencia a este hecho.

Otro ejemplo sería una función para sumar todos los elementos de una lista. Estamos pensando en valores numéricos, ¿no? Bien, la misma función es capaz de concatenar todas las cadenas de una lista, operar sobre números complejos, reales, enteros, o una mezcla de todos ellos. En realidad, sólo estamos exigiendo que los objetos (en Python, hasta los enteros son objetos) que le pasemos sea capaz de sumarse, y para ello basta con que tengan un método __add__.

Un ejemplo típico en Python es crear una clase que imita el comportamiento de los ficheros (al menos parcialmente). Hay muchas funciones en Python que esperan recibir como parámetro un objeto que cumpla la interfaz de los ficheros. Casos concretos: Funciones de depuración que vuelcan información a un fichero, codificadores, etc. Otro caso típico es el de las secuencias. Podremos hacer un bucle for sobre cualquier objeto que defina un método __getitem__. A esto se le llama emular la interfaz de las secuencias.

En nuestro caso concreto, veamos nuestra interfaz tk. ¿Qué le exigimos al parámetro tipo_db que pasamos al constructor de la clase principal? Debe ser invocable sin parámetros. Nosotros estábamos pensando en una clase, claro. Pues bien, no es necesario que tipo_db sea una clase. Podría ser cualquier función tal que, al llamarla sin parámetros, devolviera un objeto con los métodos busca y encuentra. Éstos últimos deben ser métodos que acepten un parámetro (en este caso, debe ser una cadena, pues utilizamos el parámetro en funciones que toman necesariamente una cadena como parámetro) y devuelvan, respectivamente, una secuencia o un elemento simple de la forma (clave, (nombre, dirección)).

En este caso, hemos intercambiado la interfaz de usuario, aunque sería posible cambiar el servidor de datos. Resultaría muy práctico especializar el servidor para utilizar internamente SQL, y hacer módulos para que dicho SQL se entendiera con ODBC en MS Windows, con JDBC en el caso de Jython sobre JVM o con módulos de acceso a datos db-api estándares de Python. Si se mantiene un buen diseño, seremos capaces de reutilizar todo nuestro código tanto como sea lógicamente posible. Comparado con C++, es como si todas nuestras clases fueran plantillas (templates), sin ningún esfuerzo adicional.

Esta eliminación de la burocracia tiene otras ventajas. Por ejemplo, es posible eliminar un método que ha quedado obsoleto de una clase. Sólo se quejarán los usuarios que utilicen dicho método. Es posible tambien redistribuir módulos aislados con funcionalidad añadida sin hacer nada sobre los clientes ya instalados, pues simplemente, no utilizarán las nuevas funciones, pero las antiguas seguirán funcionando tranquilamente. Nada de DLLs incompatibles en Python (sí, estoy pensando en las interfaces ActiveX). Como curiosidad, debo indicar que es muy sencillo en Python forzar la carga de unos módulos concretos e incluso tener una versión de Python completa instalada para cada programa concreto, si tenemos paranoia acerca de los componentes compartidos.

Otro aspecto, que no hemos utilizado aquí, del dinamismo de Python en ejecución es el acceso a parámetros y métodos por su nombre. Este nombre puede ser una variable, lo que nos permitiría, en el ejemplo del servidor de aplicaciones, tomar el nombre del documento solicitado por el navegador e invocar al método de dicho nombre. Sólo habría que capturar los errores y añadir una capa de seguridad para tener un servidor de aplicaciones dinámico.