domingo, 28 de febrero de 2010

Python en español - Introducción

Este post forma parte de una serie que voy a desarrollar en estos días, referente a la programación en Python. Doy por sentado que el lector sabe la procedencia de Python (lenguaje de script, semi interpretado [.pyc]), las características técnicas (orientado a objetos, multiplataforma, fuertemente tipado y cosas de esas) y lo que se puede realizar con él (desarrollo web, escritorio, telefonía móvil, etc).

Vamos a ver como programar en Python, en español. Aquí os presento la introducción.

El lenguaje de programación Python se puede descargar de la web oficial de Python, esto es, http://www.python.org/. En esta web podemos encontrar todo lo que necesitamos, a saber, documentación, enlaces externos a otros sitios web con más información, recomendaciones de IDE's para desarrollo y un largo etcétera.

Voy a hablar de Python en la plataforma Windows. Para Linux es casi idéntico, excepto en temas de directorios de instalación, por supuesto, y algunos comandos propios de sistemas posix (Linux, Unix).

Lo primero que hay que hacer para empezar a trabajar con Python, ¡¡¡es bajarse Python!!!. Esto que parece trivial no lo es tanto, y ahora se entendera porqué.

Una de las cuestiones que menos me gusta de trabajar en este lenguaje son las versiones de Python, ya que dependiendo de cada versión, para cada plataforma, nos encontramos que podemos tener módulos escritos para una versión ó no. Por ejemplo, si yo quiero utilizar Python con una base de datos MySQL que utilice el módulo mysqldb tengo el problema que para Python 3 en Windows no está el módulo mysqldb. Otro ejemplo, si quiero utilizar el módulo pymedia para manipular ficheros de sonido (wav, mp3, ogg, avi, divx, dvd, cdda etc.) solo puedo utilizar para Windows Python 2.4. ¿Se entiende el por qué de las versiones en Python? Una cosa es que guste esta plataforma de desarrollo, pero hay que entender que no es oro todo lo que reluce.

Actualmente yo no tengo instalada la última versión de Python (a la hora de escribir este post estaba por la 3.1.1). Para Windows recomiendo la 2.5.4 y no la 2.6 por temas de compatibilidad entre módulos (lo que he comentado antes). En mi caso mysqldb me funciona con la versión que tengo instalada. Aquí cada uno debe de pensar en instalarse lo que necesite.

Para descargarte Python 2.5.4 prueba en el siguiente enlace: http://www.python.org/download/releases/2.5.5/.

Una vez se descarga, instalamos y probamos que efectivamente se ha instalado. Si no se cambia nada, todo se guarda en la carpeta Python25 del directorio raíz. Lanzamos el intérprete de comandos de Windows (Inicio/Ejecutar/cmd.exe), entramos en la carpeta de Python25 y ejecutamos python.exe. Si todo ha ido bien debe de salir lo siguiente:

Para salir correctamente del intérprete, salir con quit().

Una consideración importante y recomendación es que se incluya en el path la ruta de Python, para que primero puedas ejecutarlo desde cualquier sitio, y segundo, no tengas problemas a la hora de ejecutar algunos scripts que no se guarden donde debieran (¡ó si!). Te lo aconsejo. En el siguiente screenshot te muestro donde lo puedes cambiar (por si no lo recuerdas, ¡que yo sé que lo sabes!).

Dos pinceladas más para ver en este capítulo. La primera es ver lo que se instala:

IDLE es un editor de desarrollo en Python, que para empezar es más que aceptable, con indentación y completitud de código. Module Docs nos muestra los módulos que están actualmente instalados en nuestro sistema, así como información de los mismos (clases, métodos, herencia, qué hacen y demás). Python es el intérprete de Python que hemos visto anteriormente. Python Manuals es el tutorial de Python de Guido van Rossum (el creador de Python y empleado de Google) en donde te explica todo sobre Python. En inglés. El Uninstall ni lo comento.

La segunda. Hay varias versiones del intérprete Python. Yo voy a ver una, CPython ó Python, que es la que está escrita en C. Existen versiones, como Jython que es Python escrito en Java (se pueden utilizar las librerías de Java), IronPython que es Python escrito en C# (se puede utilizar el framework .NET) ó PyPy que es un intérprete de Python escrito en Python (para rizar más el rizo!!!).

En el siguiente post referido al tema de Python en español veremos los tipos de datos.

jueves, 25 de febrero de 2010

Filosofia Pythoniana.....

Los usuarios de Python se refieren a menudo a la Filosofía Python que es bastante análoga a la filosofía de Unix. El código que sigue los principios de Python de legibilidad y transparencia se dice que es "pythonico". Contrariamente, el código opaco u ofuscado es bautizado como "no pythonico" ("unpythonic" en inglés).


Estos principios fueron famosamente descritos por el desarrollador de Python Tim Peters en El Zen de Python:

  • Bello es mejor que feo.
  • Explícito es mejor que implícito.
  • Simple es mejor que complejo.
  • Complejo es mejor que complicado.
  • Plano es mejor que anidado.
  • Ralo es mejor que denso.
  • La legibilidad cuenta.
  • Los casos especiales no son tan especiales como para quebrantar las reglas.
  • Los errores nunca deberían dejarse pasar silenciosamente.
  • A menos que hayan sido silenciados explícitamente.
  • Frente a la ambigüedad, rechazar la tentación de adivinar.
  • Debería haber una -y preferiblemente sólo una- manera obvia de hacerlo.
  • Aunque esa manera puede no ser obvia al principio a menos que usted sea Holandés (Guido es el creador y benevolente dictador vitalicio de Python, ¡y es holandés!).
  • Ahora es mejor que nunca.
  • Aunque nunca es a menudo mejor que ya.
  • Si la implementación es dificil de explicar, es una mala idea.
  • Si la implementacion es fácil de explicar, puede que sea una buena idea.
  • Los espacios de nombres (namespaces) son una gran idea ¡Hagamos más de esas cosas!.

Una última cosa. Estos principios son casi axiomáticos en Python. Es más, incluso están implementados en el intérprete Python. ¿No me crees? Ejecuta el intérprete y escribe esto:

import this

lunes, 22 de febrero de 2010

NetBeans y Python - Cambiar de plataforma

Hola de nuevo! Hay algo que me gustaría comentar, y es si se está trabajando en plataformas Linux ó Windows con NetBeans, pero con versiones de Python diferentes.

En mi caso he empezado a crear una aplicación en Linux, con Python 2.6, y luego he querido llevar el proyecto de NetBeans a una plataforma Windows con Python 2.5. Evidentemente han saltado las alarmas.


Vamos a cargar el proyecto que nos hemos traído de la otra plataforma, y le comentamos evidentemente que será el proyecto principal:



Si tenemos versiones diferentes de Python (en este caso 2.6 en Linux y 2.5 en Windows si no tenemos en Windows la 2.6 instalada claro!) nos aparecerá el siguiente error:

La manera más sencilla de arreglar esto es editar un fichero de configuración del proyecto en NetBeans y decirle que en vez de trabajar con una versión de Python lo estamos haciendo con otra.


Solo es necesario editar el fichero project.properties, tal como muestra el screenshot, y en el campo de plataforma activa modificar la versión de Python. En este caso cambiar Python_2.6.4 por Python_2.5.4, tal como se muestra en la configuración del NetBeans (esto es, el Python que tenemos instalado en nuestra máquina).

Una vez realizado el cambio, NetBeans nos deja perfectamente trabajar con este proyecto.

domingo, 21 de febrero de 2010

Prototipados en Python - Fácil y sencillo

Vamos a crear prototipo de un sistema de reconocimiento de texto por voz en Python, y multiplataforma, que funcione tanto en Windows como en Linux.

Este programa es un prototipo de una aplicación que debería ser mucho más sofisticada, sobretodo en la reproducción del texto. Es importante, ya que aquí se está escribiendo una aplicación rápida, un prototipado. El resultado final no es de una calidad profesional como el software comercial que hay actualmente en el mercado (evidentemente). Una de las cosas fuertes que tiene Python es el prototipado de aplicaciones.

El propósito de crear esta aplicación es ver, primero, la realidad de la portabilidad de Python entre varias plataformas (en este caso Linux y Windows). En segundo lugar, la reproducción de sonidos en nuestros programas escritos en Python y en tercer lugar, el manejo de uno de los tipos de datos más importantes de Python, el diccionario.

Este proyecto lo voy a realizar con Python 2.6, en una máquina Linux Ubuntu 9.10. ¿Por qué? Pues por la sencilla razón que el 17 de Febrero de 2010, a las 9:45 de la mañana, mi flamante Windows XP SP3 dijo que no arrancaba. Estuve todo el día para poder obtener la información del disco, y al final lo conseguí. Puesto que tengo un disco de 100 Gb, he creado 6 particiones: 1 Windows 2000, 1 Windows XP, 1 Linux (y por ende 1 swap), y 2 particiones, en FAT32, para intercambiar información entre varios sistemas (Linux lee NTFS, pero Windows no lee ext4, ¡cosas de la vida!).
Este proyecto tenía en mente hacerlo con EDITRA, pero tengo un problema, no me deja ejecutarlo (en Ubuntu 9.10). Mientras que no consiga arreglar el problema voy a empezar con el proyecto en NetBeans, ya que tiene un plugin para Python.


Bien, lo primero de todo hay que ver qué es lo que queremos, para de esta manera segmentar el trabajo. A ver, todo lo voy a hacer yo, ya que es un prototipo (en donde el trabajo se realiza rápidamente), pero si no lo fuera, habría un equipo de trabajo en donde se planificaría el mismo: menos tiempo programando, ¡y no se está tan solo!.

OBJETIVO: Crear una aplicación que tome como entrada un fichero de texto plano en español. La aplicación irá reconociendo el texto, y reproducirá en el altavoz de la máquina el sonido de las palabras que encuentre. La relación entre las palabras y su sonido lo tendremos que generar nosotros previamente. Es decir, hay que grabar todas las palabras que queramos que se reproduzcan, en un grabador, para poder asociarlas a las palabras del texto.

Si fuéramos un equipo de trabajo habría que diferenciar 3 aspectos diferentes. Primero, la creación de estructuras y acceso al sistema de ficheros. Segundo, la creación de ficheros de sonido de palabras en español y su reproducción. Y tercero, las pruebas y ajustes de alguien que en principio no estuviera implicado en los dos anteriores pasos, para poder ser objetivo (un lingüista). Hay que tener en cuenta que esto debería estar supervisado por alguien que conociera perfectamente el objetivo final del mismo proyecto, para poder coordinar esfuerzos, motivación del grupo y rectificaciones del trabajo in situ.

Los puntos del desarrollo son los siguientes:
  • Sistema para poder obtener un fichero de texto y cargarlo en algún tipo de estructura.
  • Sistema para poder relacionar una palabra con un sonido.
  • Grabación de palabras y su reproducción.
  • Sistema de reproducción de las palabras que están en la estructura de datos que hemos creado.
  • Pruebas y ajustes.
  • Paso a producción.
PASO 1: Grabación de palabras.

Como antes hemos comentado, relacionamos cada palabra con un fichero de sonido, que tendremos que grabar. Una aplicación en Ubuntu para grabar ficheros de sonido OGG es el grabador de sonidos de Gnome, el gnome-sound-recorder. El fastidio aquí­ es que hay que grabar por cada palabra que queramos reproducir. Hay que tener en cuenta que esto es un proyecto muy básico (un prototipo) para ver la potencia de Python en desarrollar aplicaciones rápidamente. Podríamos hacerlo mucho más profesional, complicando el tema, pero no es el caso.


Como vemos en el screenshot (captura de pantalla) de arriba, vamos grabando palabras, en formato OGG. ¿Cómo creamos una relación de estas grabaciones? Creamos a continuación un fichero, llamado aquí lista_ficheros.ini, que contendrá por cada línea una palabra, un espacio en blanco, y el nombre del fichero OGG que hemos grabado con el sonido acorde a la palabra que le acompaña. En el screenshot de arriba se puede ver las palabras que he grabado, y la relación en el fichero.

PASO 2: Reproducción en Python.

¿Cómo vamos a reproducir un sonido en Python? Mirando por algunos blogs de geeks en Python me he decicido, para la plataforma Linux, pygame, el módulo para programar juegos de Python. Hay otras opciones que he estado probando, como el framework gstreamer ó pysonic, pero el más sencillo me ha parecido este. Decir que pygame no viene de serie en Python, por lo que hay que descargarlo, tanto en plataformas Linux como Windows (y también en Mac, pero no hablaré de ella). Para Linux, si estáis trabajando en Ubuntu, podéis elegir dos maneras para bajarlo de Internet, a saber, utilizando el gestor de paquetes de Synaptic ó bien hacerlo a la manera tradicional, esto es, "apt-get install python-pygame". Más información de este módulo en http://www.pygame.org/.

Un ejemplo de cómo funciona el módulo pygame es lo que vamos a ver a continuación. Lo único que hace este código es reproducir un sonido, y mientras que se está reproduciendo estará en un estado de bloqueo (get_busy() devuelve True mientras que se está reproduciendo algo).


import pygame
import os

pygame.mixer.init()
pygame.mixer.music.load(os.path.realpath("prueba.ogg"))
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
pass
print "Terminé con el sonido"

En este código importamos módulos necesarios, cargamos fichero de sonido, reproducimos y creamos un bucle que se estará ejecutando mientras que haya sonido reproduciéndose. Fácil y sencillo.

PASO 3: Módulo que implementa el tratamiento de sonido y la relación entre palabras y sus sonidos correspondientes.

He creado el módulo sonido.py, en donde creo un clase diccionario_palabras (con ciertos métodos claro!). Esta clase lo único que hacer es acceder a un fichero que tendrá una correspondencia entre una palabra y un fichero de sonido, y mediante sus métodos se puede manipular la información suministrada.

Esta relación la guardamos en una estructura diccionario, ya que en realidad es una tabla hashing (llave, dato asociado). Evidentemente la llave (palabra) no puede repetirse, aunque si el nombre del fichero. El código de sonido.py es el siguiente:

# -*- coding: cp1252 -*-

import os
import pygame

class diccionario_palabras(object):
def __init__(self,lista_fichero):
'''
Constructor. Se le pasa como parámetro el fichero que contendrá
la lista de correspondencia entre palabras y fichero de sonido .ogg.
El fichero lista tiene que tener la siguiente estructura:
palabra1 fichero_sonido_palabra1.ogg
palabra2 fichero_sonido_palabra2.ogg
...
palabraN fichero_sonido_palabraN.ogg
'''
self.__lista_palabras = []
self.diccionario = {}
try:
# Abrimos fichero de asociación de palabras.
fichero = open(lista_fichero,'r')
# Cargamos cada línea de fichero como una tupla (palabra, fichero wav)
while True:
linea = fichero.readline()
if not linea:
break
# Separamos el nombre de la palabra del fichero de sonido asociado a la palabra.
linea = linea.split()
# Insertamos en la lista de palabras la lista [palabra, nombre de fichero]
self.__lista_palabras.append(linea)
# Creamos un diccionario de palabras con su sonido asociado.
self.diccionario = dict(self.__lista_palabras)
# Cerramos el fichero.
fichero.close()
# Info.
except:
print "Ha habido un error a la hora de crear el diccionario!"

def reproducir_palabra(self, fichero):
'''
Reproduce el sonido del fichero pasado como parámetro.
'''
try:
# Iniciamos pygame.
pygame.mixer.init()
# Cargamos fichero con el sonido.
pygame.mixer.music.load(fichero)
# Reproducimos el sonido.
pygame.mixer.music.play()
# Esperamos a que termine.
while pygame.mixer.music.get_busy():
pass
except:
print "No puedo reproducir el fichero ", fichero

def obtener_sonido_palabra(self,palabra):
'''
Devuelve el nombre del fichero asociado a la palabra.
'''
ret = self.diccionario[palabra]
return ret

def palabra(self,palabra):
fichero = self.obtener_sonido_palabra(palabra)
self.reproducir_palabra(os.path.realpath(fichero))

def listar_diccionario(self):
print "El diccionario es :", self.diccionario

Como puede observarse, la clase es muy sencilla, y los métodos obvios. En el constructor obtenemos los datos que necesitamos, incluyéndolos en un diccionario y mediante el método reproducir_palabra reproducimos el fichero que se especifica.

PASO 4: Carga del fichero que contiene el texto plano en español en una estructura, para tratarlo.

Esto puede hacerse de manera sencilla mediante una función que recoga todas las líneas del fichero y las incluya en una lista de listas, donde cada lista sea una línea del fichero. Si lo hago de esta manera es para el tratamiento de la información, ya que mediante listas en Python es casi trivial, como veremos a continuación. La función, denominada cargar_fichero, es la siguiente:

def cargar_fichero():
'''
Carga un fichero en una estructura de datos. Devuelve una lista de listas,
donde cada lista es una línea

'''
nom_fich = raw_input("Introduce nombre del fichero de texto ==> ")
try:
# Creamos una lista de listas, esto es, una lista que contendrá
# listas (donde cada lista en una línea del fichero).
lineas = []
# Abrimos fichero.
fichero = open(os.path.realpath(nom_fich),'r')
# Tratamos cada línea del fichero.
while True:
linea = fichero.readline()
if not linea:
break
# Separamos las palabras en la línea.
linea = linea.split()
# Vamos añadiendo líneas a la lista.
lineas.append(linea)
# Cerramos fichero.
fichero.close()
except:
print '''

¡¡¡¡ NO HE PODIDO ABRIR EL FICHERO !!!!

'''
nom_fich = ""
continuar()
# Devolvemos la lista con las filas del fichero.
return lineas, nom_fich

La función está lo suficientemente comentada como para ver lo que hace. Esto también es bastante fácil. Como se podrá observar, por el momento no hemos hecho algo que sea de días de trabajo. Para prototipados, Python, sin lugar a dudas.

NOTA IMPORTANTE: Esta función, y otras que necesito, las voy a incluir en un fihcero aparte, para ser ordenados (esto es muy importante) y poder reutilizar código en un futuro. El fichero se llama recursos_voz.py, y el código viene a continuación (incluyo la función de carga del fichero de texto de arriba):

# -*- coding: cp1252 -*-

import os

def menu(fichero):
# Limpiamos pantalla.
if os.name == "posix":
os.system("clear")
if os.name == "nt":
os.system("cls")

print '''

***********************************
APLICACIÓN DE REPRODUCCIÓN DE TEXTO
***********************************
'''
if len(fichero)!=0:
print "\t"
print "\t","\t","Fichero ", fichero, " cargado!"

print '''

Elige una de las siguientes opciones:

1) Cargar fichero de texto.
2) Reproducir fichero.
3) Ayuda.
0) Salir.

Elige opción:
'''
opcion = raw_input(" ")
return opcion

def continuar():
raw_input("Pulsa cualquier tecla para continuar")

def ayuda():
print '''

Esta es una aplicación que lee, a partir de un fichero de texto
plano, el contenido del mismo, con ayuda de un diccionario de palabras,
que tiene una correspondencia entre palabras y sus sonidos correspondientes.

* La opción 1 sirve para cargar en la aplicación el fichero de texto que
se quiere analizar.

* La opción 2 sirve para analizar el fichero introducido en la opción 1,
reproduciendo las palabras que hay en dicho archivo. Si no encuentra la
palabra, simplemente no la reproduce. Si quieres añadir más palabras solo
tienes que editar el fichero diccionario adjunto a la aplicación, cuyo
formato es: palabra fichero_sonido_palabra.ogg

Graba una palabra con tu grabador favorito en formaro OGG, asóciala a la
palabra que quieras y listo!!!

* La opción 3 es esta ayuda.

* Para salir pulsa 0.

'''
continuar()

def cargar_fichero():
'''
Carga un fichero en una estructura de datos. Devuelve una lista de listas,
donde cada lista es una línea

'''
nom_fich = raw_input("Introduce nombre del fichero de texto ==> ")
try:
# Creamos una lista de listas, esto es, una lista que contendrá
# listas (donde cada lista en una línea del fichero).
lineas = []
# Abrimos fichero.
fichero = open(os.path.realpath(nom_fich),'r')
# Tratamos cada línea del fichero.
while True:
linea = fichero.readline()
if not linea:
break
# Separamos el nombre de la palabra del fichero de sonido asociado a la palabra.
linea = linea.split()
# vamos añadiendo líneas a la lista.
lineas.append(linea)
# Cerramos fichero.
fichero.close()
except:
print '''

¡¡¡¡ NO HE PODIDO ABRIR EL FICHERO !!!!

'''
nom_fich = ""
continuar()
# Devolvemos la lista con las filas del fichero.
return lineas, nom_fich

Este es un fichero de recursos, como bien indica su nombre. Podemos observar que nuestra aplicación tiene una interfaz en consola de comandos (ver función menu()). Podría ser interesante crear una interfaz en wxPython, pero por rapidez no lo he hecho. De todas formas, es muy importante que cuando se haga un proyecto de este tipo, sea lo más independiente de una plataforma gráfica (siempre que se pueda), ya que de esa manera se puede implementar de varias formas, a saber, Tkinter ó Qt, por poner ejemplos, como interfaces gráficas.

Otra cosa a indicar es que la portabilidad de la aplicación nos la aseguramos en la función menu(). Fijarse en que según la plataforma en la que nos encontremos, el comando de limpiar la pantalla cambia. Si queremos que funcione en Windows y Linux hay que fijarse en estos detalles.


   # Limpiamos pantalla.
if os.name == "posix":
os.system("clear")
if os.name == "nt":
os.system("cls")


PASO 5: Diseño de introducción de datos.

Por último hay que crear el módulo que se ejecutará. Lo llamamos voz.py, y en él se hace referencia a los módulos que hemos creado previamente, sonido.py y recursos_voz.py. El funcionamiento es muy simple. Aparece un menú, con opciones. La primera opción sirve para cargar un fichero de texto, la segunda para analizarlo. Una opción de ayuda y otra para salir de la aplicación. El código de voz.py se muestra a continuación:

# -*- coding: cp1252 -*-

import os.path
from sonido import diccionario_palabras
from recursos_voz import *

# Cargamos diccionario de correspondencia entre palabras y sonidos.
nombre_fichero = os.path.realpath('lista_ficheros.ini')
diccionario = diccionario_palabras(nombre_fichero)

opcion = ""
cabecera = ""
while opcion != "0":
opcion = menu(cabecera)
if opcion == "1":
# Indicamos el fichero de texto, para cargarlo en una estructura.
lineas = []
lineas, cabecera = cargar_fichero()

if opcion == "2":
# Procesamos el fichero cargado.
try:
for linea in lineas:
for palabra in linea:
try:
diccionario.palabra(palabra)
except:
print "Palabra ", palabra, " no está en diccionario!"
continuar()
except:
print "Pimero tienes que cargar un fichero!!!"
continuar()
if opcion == "3":
# Mostramos ayuda.
ayuda()

print "Hasta pronto!"

En este módulo hay que dar mención especial a la potencialidad de las listas, en donde podemos ver como tratar las palabras de las líneas del fichero. Véase a continuación:

try:
for linea in lineas:
for palabra in linea:
try:
diccionario.palabra(palabra)
except:
print "Palabra ", palabra, " no está en diccionario!"
continuar()
except:
print "Pimero tienes que cargar un fichero!!!"
continuar()

Sencillamente vamos tratando en cada línea (del total), el conjunto de palabras ue lo forman. Se puede observar que la sintaxis es muy sencilla de leer y entender. Otro punto a favor de Python!!!

PASO 6: Crear ejemplos para realizar pruebas.

Crear cualquier fichero de texto plano, e incluir una frase ó frases que contengan palabras que hemos grabado, eveidentemente, para hacer pruebas.

PASO 7: Paso a producción.

Ejecutamos la aplicación, mediante:

python voz.py

Una captura de cómo tiene que quedar el programa sería esta:

Os aseguro que funciona tanto en Windows como en Linux, ya que lo he probado en las dos plataformas.

Espero os haya gustado, lo fácil y sencillo que es programar prototipos en Python.

lunes, 15 de febrero de 2010

Bibliografía informática - Hay joyas que nunca pasan de moda

Hace unos días estuve en un blog y me impactó un artículo sobremanera. Hablaba sobre la bibliografía básica que todo el mundo debe tener a la hora de decicarse a esto de la informática. Debo de decir que no tenía ningún libro de los que ahí se mencionaron, ni siquiera me sonaban los autores. Debe ser que estoy desactualizado, o que la gente a la que leo no tiene buen material, o que lo que yo considero bibliografía sagrada está ya obsoleta.

El caso es que también me he decidido a escribir un post refiriéndome a bibliografía básica informática, segmentada por temas, claro. Podré estar desactualizado, pero creo que hay cosas que hay que ver, aunque sea por pura anécdota. Es más, no hace mucho hablé con alguien que se supone sabe las mil y una noches de programación... vamos que yo no le llegaba a los pies. Y quizás lleve razón... es más, la lleva. Pero cuando le pregunté si conocía la obra de Donald Knuth, y me dijo que ese no sabía quien era..... No sé... es como el que dice saber mucho de coches y no sabe quien es Henry Ford, o por lo menos haber oido hablar de él.

Todos los libros que aquí presento son parte de mi biblioteca personal. De todos he leído capítulos enteros. No voy a mentir y decir que me los he leído todos desde el principio al final, porque no es cierto, pero si la mayoría de sus capítulos. He puesto los que a mi parecer, son los más representativos de las disciplinas que más me interesan (evidentemente hay muchas más referencias obligadas). Cada uno tiene sus gustos. Yo aprendí con estos libros, y creo que los que los escribieron algo tendrían que decir.

Programación. Fundamentos.

Título: El arte de programar ordenadores - Clasificación y búsqueda.
Autor: Donald Knuth
Editorial: Reverté SA
Obsevación: Biblia de la algoritmia en clasificación y búsqueda.

Título: Estructura de datos y algoritmos.
Autores: Aho, Hopcroft y Ullman
Editorial: Pearson
Observación: Referencia fundamental en la programación con punteros. Una joya pedagógica.

Título: Algoritmos y estructura de datos
Autor: Niklaus Wirth
Editorial: Prentice Hall
Observación: Un clásico. Tipos de datos. Estructuras con punteros. Básico.

Título: Esquemas algorítmicos fundamentales.
Autor: Scholl y Peyrin.
Editorial: Masson
Observación: Para aprender a programar desde cero. Es el libro de referencia de la programación estructurada. Excelente el enfoque de máquina secuencial de caracteres.

Título: Fundamentos de algorítmia
Autor: Brassard y Bratley
Editorial: Prentice Hall
Observación: Temas de programación avanzada. Algorítmica a gran nivel. Referencia obligatoria.

Programación. Lenguajes y sistemas.

En este apartado voy a indicar los que mas me han marcado, tanto por su nivel pedagógico como por su nivel técnico elevado. en los temas específicos de programación de sistemas y programación orientada a objetos.

Título: El lenguaje de programación C.
Autores: Kernighan y Ritchie.
Editorial: Prentice Hall.
Observación: Obra de arte. Como en un libro tan pequeño se puede contar tanto, y tan bien.

Título: UNIX Programación avanzada.
Autor: Márquez
Editorial: Ra-ma
Observación: Referencia fundamental en la programación en sistemas UNIX. El tema de sockets, simplemente brillante.

Título: Introducción a la programación con orientación a objetos.
Autores: Camelia Muñoz, Alfons Niño, Aurora Vizcaíno.
Editorial: Prentice Hall
Observación: Excelente libro para aprender desde cero a programar con orientación a objetos. Alto nivel pedagógico, sin meterse demasiado en el lenguaje con el que se trata el tema (Java). Me ha gustado muchísmo.

Bases de datos.

En este apartado se podrían decir multitud de referencias, y muchas más si nos dedicamos a ver cada sistema gestor de bases de datos. Yo sólo voy a incluir un libro.

Título: Fundamentos de sistemas de bases de datos.
Autor: Elmasri y Navathe.
Editorial: Addison Wesley.
Observación: Fundamental en bases de datos. Lo ve todo.

Redes.

Título: Redes de computadoras.
Autor: Tanenbaum.
Editorial: Pearson.
Observación: Hablar de redes sin hacer mención del Tanenbaum es absurdo.

Título: Redes de computadores - Un enfoque descendente basado en Internet.
Autores: Kurose y Ross.
Editorial: Pearson - Addison Wesley.
Observación: Manual más actualizado para ver el tema de redes en profundidad.

Sistemas operativos.

Título: Sistemas operativos.
Autor: Stallings.
Editorial: Prentice Hall.
Observación: Manual fundamental de sistemas operativos.

Título: Sistemas operativos - Diseño e implementación.
Autores: Tanenbaum y Woodhull.
Editorial: Prentice Hall.
Observación: Evidentemente, el Tanenbaum de SO. Nada más que decir.

Sistemas.


Título: Lenguaje ensamblador y programación para PC IBM y compatibles.
Autor: Peter Abel.
Editorial: Prentice Hall.
Obervación: Referencia fundamental en la programación en ensamblador. Es un libro antiguo, y desfasado, pero explica de una manera formidable, con multitud de ejemplos el funcionamiento de un PC por dentro (ALU, registros, interrupciones y un largo etcétera). De los pocos libros que me leido por completo.

Título: Organización y diseño de computadoras - La interfaz hardware/software.
Autores: Patterson y Hennessy.
Editorial: McGraw Hill.
Observación: La biblia del diseño de computadoras. Fundamental.

Para mí estos son los libros fundamentales que se deberían ver, o por lo menos saber que existen, ya que forman parte de la base de la informática. Puede que esté desactualizado en ciertas materias, pero lo cierto es que no he visto ninguna referencia a estos libros, ni siquiera a uno, del blog en el que estuve hace unos días.

Y es que después de los años que han pasado, miro con añoranza estos libros, y de vez en cuando da gusto leerlos. Para los que nos gusta nuestra profesión (yo soy informático convencido) hay joyas que nunca pasan de moda.

domingo, 14 de febrero de 2010

MySQL y Python - Relación de pura potencia y 3

Inserción, actualización y borrado de filas: INSERT, UPDATE y DELETE.

Efectivamente podemos utilizar las instrucciones insert, update y delete vía módulo MySQLdb. En este apartado podemos ver 3 casos a la hora de la construcción de la sentencia:

1) Sentencia SQL sin parámetros (SQL estático). La sentencia se puede crear como una cadena de caracteres, sin incluir ningún tipo de valor o variable ó construcción adicional. Por ejemplo:

# -*- coding: cp1252 -*-
# Importamos módulo
import MySQLdb

# Intentamos conectar con la base de datos.
try:
conexion = MySQLdb.connect(host = "localhost", \
user = "root", passwd = "1234",db = "pruebas_python")
print "Conexión realizada"
except:
print "Error en conexión"

# Creamos cursor a partir de la conexión realizada.
cursor = conexion.cursor()

# Creamos sentencia SQL.
cadenaSQL = 'update cliente set nombre = "G. Almaraz" where id = 12'

# Ejecutamos sentencia SQL.
try:
cursor.execute(cadenaSQL)
conexion.commit()
except:
conexion.rollback()

# Cerramos conexión
conexion.close()
Cambiamos, en la fila con id = 12, el contenido del campo nombre (antes tenía la cadena 'Gabriela' y ahora 'G. Almaraz'). Como podemos observar siempre hay que cerrar una conexión, mediante el método close del objeto conexion. Cuando ejecutamos la sentencia SQL, si todo ha ido bien, hacemos commit, de lo contrario, rollback.

2) Sentencia SQL con parámetros (SQL dinámico). En este caso la sentencia SQL no está formada previamente por defecto, sino que necesita de unos datos adicionales para poder formar dicha sentencia. Por ejemplo:

# Creamos cursor a partir de la conexión realizada.
cursor = conexion.cursor()

# Pedimos datos.
nombre = raw_input("Introduce nombre: ")
ciudad = raw_input("Introduce ciudad: ")

# Creamos cadena de inserción.
cadenaSQL = 'insert into cliente (nombre, ciudad) values (%s, %s)'

# Ejecutamos
try:
cursor.execute(cadenaSQL, (nombre, ciudad))
conexion.commit()
except:
print "Hubo Error"
conexion.rollback()

# Cerramos conexión
conexion.close()

En este caso ciertos valores de la sentencia SQL son introducidos por el usuario. %s se utiliza para representar cada variable en la sentencia SQL, y cuyos valores están guardados en una tupla pasada como segundo argumento al método execute del objeto cursor.

3) Sentencias SQL que se ejecutan múltiples veces. En ocasiones se presenta el crear una sentencia SQL (como un insert, por ejemplo) y ejecutarla una y otra vez con diferentes valores. El módulo MySQLdb viene integrado con un método, denominado executemany, el cual simplifica la tarea y reduce costes de tiempos. El ejemplo siguiente lo aclara todo:

# Creamos cursor a partir de la conexión realizada.
cursor = conexion.cursor()

# Creamos lista de datos.
lista_datos = [('nombre1', 'ciudad1'),('nombre2', 'ciudad2'),('nombre3', 'ciudad3')]

# Creamos cadena de inserción.
cadenaSQL = 'insert into cliente (nombre, ciudad) values (%s, %s)'

# Ejecutamos
try:
cursor.executemany(cadenaSQL, lista_datos)
conexion.commit()
except:
print "Hubo Error"
conexion.rollback()

# Cerramos conexión
conexion.close()
Mediante executemany hacemos 3 inserts de golpe (uno tras otro), en una única sentencia.

El origen de datos es una lista de tuplas. Cada elemento de la lista es una tupla que contiene los valores para cada iteración. Cada tupla es una fila.

Último ID incremental

En caso de tener campos de autoincremento en una tabla, se puede utilizar el método
insert_id del objeto conexion para obtener el identificador de la última fila insertada. Esto es interesante si necesitamos dicha información para relacionar unas tablas con otras a través de identificadores foráneos y cosas por el estilo.

El siguiente ejemplo lo aclara todo:


# Creamos cursor a partir de la conexión realizada.
cursor = conexion.cursor()

# Creamos cadena de inserción.
cadenaSQL = 'insert into cliente (nombre, ciudad) values ("FIN","FIN")'

# Ejecutamos
try:
cursor.execute(cadenaSQL)
id = int(
conexion.insert_id())
conexion.commit()
# Obtenemos el último identificador incremental de la última fila insertada.
print "ID de la última fila insertada: ", str(id)
except:
print "Hubo Error"
conexion.rollback()

# Cerramos conexión
conexion.close()
Este código, si hemos realizado los ejemplos al pie de la letra y sin equivocarnos, debe de dar como resultado lo siguiente:

Conexión realizada
ID de la última fila insertada: 17

Ahora nuestra tabla ejemplo debe de estar con los siguientes datos:

MySQL y Python - Relación de pura potencia y 2

Continuamos viendo formas de obtener datos...

2) Utilizando el método fetchone. Mediante este método del objeto cursor se pueden obtener y mostrar filas una a una, en vez de todas a la vez (lo que ocurría con fetchall). Veamos el siguiente ejemplo:


# Importamos módulo
import MySQLdb

# Intentamos conectar con la base de datos.
try:
conexion = MySQLdb.connect(host = "localhost", \
user = "root", passwd = "1234",db = "pruebas_python")
print "Conexión realizada"
except:
print "Error en conexión"

# Creamos cursor a partir de la conexión realizada.
cursor = conexion.cursor()

# Ejecutamos sentencia SQL.
cursor.execute("SELECT * FROM cliente")

# Obtenemos el número de filas del resultado de hacer la consulta select.
numero_filas = int(cursor.rowcount)

# Obtenemos y mostramos una fila a la vez (en cada iteración).
for fila in range(0,numero_filas):
fila = cursor.fetchone()
print str(fila[0]), " - " , str(fila[1]).strip(), " (", str(fila[2]).strip(), ")"
El método rowcount() del objeto cursor se utiliza para obtener el número de filas del resultado de hacer la consulta SQL. Este número se utiliza en un bucle for para iterar sobre el resultado, mediante el método fetchone. Con este método nos movemos a través del conjunto de filas resultado, de manera que podemos visualizar el contenido de cada fila, en cada iteración.

3) Utilizando el método fetchmany. Mediante este método podemos obtener un subconjunto del conjunto resultado de una consulta. Podemos especificar el tamaño de las filas que queremos que se nos devuelvan como resultado. Véamoslo con el siguiente ejemplo.

# Ejecutamos sentencia SQL.
cursor.execute("SELECT * FROM cliente")

# Limitamos el resultado de la consulta a 5 filas del total.
ret = cursor.fetchmany(5)

# Iteramos sobre el resultado devuelto.
for fila in ret
print str(fila[0]), " - " , str(fila[1]).strip(), " (", str(fila[2]).strip(), ")"
En consecuencia nos devuelve únicamente las primeras 5 filas que encuentre la sentencia select definida en el método execute.

4) Mediante el método scroll. Con este método podemos movernos dentro del conjunto de filas resultado del cursor, dando una nueva posición a partir de la cual devolver información. Hay dos tipos de modo de funcionamiento, mediante desplazamiento relativo (relative) a la posición actual en el conjunto de filas resultado y desplazamiento absoluto (absolute), si la posición de las filas tiene un valor absoluto. Por defecto el método scroll tiene modo de funcionamiento "relative". Esto hay que verlo en un ejemplo, que es muy complicado explicarlo:

# Ejecutamos sentencia SQL.

cursor.execute("SELECT * FROM cliente")

# Obtenemos y mostramos la cuarta fila directamente.

ret = cursor.scroll(3)
ret = cursor.fetchone()
print ret

# Avanzamos una posición relativa, y vamos a la sexta fila. Darse cuenta que
# aquí no iríamos a la quinta fila, ya que el último fetchone mueve una
# posición dentro del cursor.

ret = cursor.scroll(1)
ret = cursor.fetchone()
print ret

# Avanzamos una posición relativa, visualizamos la octava fila.

ret = cursor.scroll(1)
ret = cursor.fetchone()
print ret

# Retrasamos una posición el cursor, visualizando de nuevo la octava fila.
# Darse cuenta que el último fetchone nos deja en la novena fila. Lo que
# hacemos mediante el método scroll aquí es decirle que retrase una posición
# (-1) dentro del cursor.

ret = cursor.scroll(-1)
ret = cursor.fetchone()
print ret

# Visualizamos mediante una posición absoluta la fila número 12. Aquí ya no
# existen los desplazamientos relativos a una posición dada del cursor. Aquí
# el desplazamiento es absoluto respecto del origen (la posición de la primera
# fila).

ret = cursor.scroll(11,'absolute')
ret = cursor.fetchone()
print ret
Como resultado este código daría lo siguiente:

(4L, 'Mar\xeda', 'La Uni\xf3n')
(6L, 'Ana', 'Murcia')
(8L, 'Emilia', 'El Llano del Beal')
(8L, 'Emilia', 'El Llano del Beal')
(12L, 'Gabriela', 'Barcelona')

MySQL y Python - Relación de pura potencia I

No creo que en este momento en el que nos encontramos haya alguien que no haya oido hablar del sistema gestor de bases de datos MySQL.

Prácticamente todo el mundo conoce este sistema y lo relaciona junto con los paquetes de software Apache (servidor) y PHP (lenguaje de script para creación de páginas web). Y en cierto sentido es así, ya que este SGBD se ha hecho muy popular por su gran rendimiento y por su escaso coste. No hace mucho MySQL fue adquirido por Sun, y ahora no se bien como está el tema de licencias. Como cabe esperar, para empresas que quieran soporte y cosas de esas habrá un MySQL de pago. De todas formas MySQL sigue siendo software libre, y vamos a hablar en este post sobre él y la magnífica relación que mantiene con Python, mediante el módulo MySQLdb (creado por Andy Dustman).

Antes de empezar supongo que todos sabemos lo que es una base de datos, lo que es un cursor, tablas, campos, selects, inserts, .... y un largo etcétera. Yo no soy ningún experto en bases de datos, pero si un fan de MySQL, por varios motivos: es gratuito, muy potente, ligero, fácil de configurar e instalar, soporta transacciones (y bloqueo de registros e integridad referencial mediante InnoDB), y en español!!!.

Podemos descargarnos el SGBD MySQL desde su página web, http://www.mysql.com/. Además, también puede interesarnos ciertas herramientas para trabajar con este sistema gestor, como son:

- MySQL GUI Tools: Paquete de tres herramientas gráficas para facilitar el uso de MySQL: MySQL Administrator 1.2 (consola de administración gráfica), MySQL Query Browser 1.2 (para crear, ejecutar y optimizar consultas SQL) y MySQL Migration Toolkit 1.1 (para migrar esquemas y datos desde varias bases de datos relacionales -Oracle, Microsoft SQL Server, Microsoft Access, etc.- a MySQL 5.0 o posterior).

- MySQL WorkBench: Herramienta de diseño de bases de datos para MySQL. Se pueden crear y editar objetos tales como tablas, rutinas y vistas y su representación visual en la pantalla permite comprender fácilmente y trabajar eficientemente con esquemas de bases de datos complejos y simples (antes de instalar MySQL WorkBench, se necesita tener instalado .NET Framework 2.0).


- phpMyAdmin: Herramienta escrita en PHP 5.2 (o posterior) para la administración de MySQL 5.0 (o posterior) a través de la web (si por cualquier razón se tuviera instalado Apache y PHP).

También podemos encontrarnos MySQL en ciertos "paquetes integrados" para la programación en web, como Instant Rails 2.0 (es un paquete que instala Ruby, Rails, Apache y MySQL y permite crear aplicaciones Ruby on Rails en un entorno autónomo), EasyPHP 5.3.0 (paquete que combina Apache 2.2.13, MySQL 5.1.37 y PHP 5.3.0. También incluye phpMyAdmin), AppServ 2.5.10 (paquete que combina Apache 2.2.8, MySQL 5.0.51b y PHP 5.2.6. También incluye phpMyAdmin 2.10.3), Uniform Server 5.5.a (paquete con Apache 2.2.14, MySQL 5.1.41 y PHP 5.2.12. Este paquete está configurado para un entorno de producción), WampServer 2.0.i (paquete que combina Apache 2.2.11, MySQL 5.1.36 y PHP 5.3.0. También incluye PECL, SQLitemanager y phpmyadmin.) ó XAMPP 1.7.3 (paquete que combina el servidor Apache 2.2.14, la base de datos MySQL 5.1.41 y el lenguaje de programación PHP 5.3.1. También incluye PEAR, Perl, mod_php, mod_perl, mod_ssl, OpenSSL, phpMyAdmin 2.11.9.2, Webalizer, Mercury Mail Transport System para Win32 y NetWare Systems, JpGraph, FileZilla FTP Server, mcrypt, eAccelerator, SQLite, y WEB-DAV + mod_auth_mysql. Este paquete está configurado para un entorno de desarrollo, no de producción.) Evidentemente habrá muchos otros más, aquí es solo un pequeño ejemplo de lo extendido que está MySQL y de sus posibilidades, especialmente la relación que mantiene con PHP.

Antes de empezar cabe decir que lo que vamos a comentar aquí es para las versiones de MySQL 5 y posteriores. La versión de Python que utilizo es la 2.5.4 y la versión 1.2.2 de MySQLdb.

MySQL y Python... ¿cómo?... la culpa la tiene la alcahueta de MySQLdb.

Python es un lenguaje orientado a objetos que usa módulos que se importan y utilizan en los programas que escribimos. Hay un módulo, que podemos descargar de http://sourceforge.net/projects/mysql-python/, llamado MySQLdb, que sirve para poder conectar una aplicación Python a un sistema gestor MySQL. Este módulo permite a los programadores hacer de todo, a saber, ejecutar comandos SQL, recoger el resultado de consultas SQL en un formato de lo más simple (una tupla de tuplas, esto es, una tupla de filas), y demás, de una manera muy fácil y sencilla.

Para trabajar con este sistema basta tener instalado Python, MySQL y el módulo MySQLdb. Opcionalmente, si quieres hacer o crear fácilmente bases de datos y tablas para usarlos con los ejemplos te recomiendo un administrador, tal como PHPMyAdmin (si tienes Apache y PHP) ó MySQL Administrator (si solo tienes instalado el MySQL). Pero hay que tener claro que aquí se habla de MySQL y Python, relacionándose con el módulo MySQLdb.

Para saber de métodos y atributos del módulo MySQLdb, una vez descargado podemos irnos a la documentación de Python e investigar un poco. Esto es:

En esta ayuda se nos detallan todas las clases que tiene, sus métodos, parámetros y demás. Si necesitas algún tipo de ayuda o quieres saber más sobre las características de MySQLdb, mira aquí. Por ejemplo, para la clase cursor podemos ver los métodos que tiene, y su explicación:

Yo he instalado MySQL, con usuario root y clave de acceso 1234. Evidentemente no es lo apropiado, pero para aprender basta.

Creamos una base de datos, llamada pruebas_python, con una tabla, cliente, y ciertos campos para usarla de conejillo de indias.


Por último insertamos ciertas filas en la tabla...

Bueno.... ya hemos visto mucho de MySQL. Viendo las capturas de pantalla nos damos una idea de lo que vamos a utilizar (datos de conexión, tablas, campos, información de campos). Ahora entramos en Python. Tenemos instalado MySQLdb. Comenzamos!

Conexión a la base de datos.

Importamos el módulo MySQLdb y creamos un objeto conexión, mediante los parámetros
específicos para poder conectar con la base de datos pruebas_python.


import MySQLdb

try:
conexion = MySQLdb.connect(host = "localhost", \
user = "root", passwd = "1234",db = "pruebas_python")
print "Conexión realizada"
except:
print "Error en conexión"


También podría habernos interesado crear la conexión sin especificar la base de datos, esto es:

conexion = MySQLdb.connect(host = "localhost", user = "root", passwd = "1234")

Una conexión correcta devuelve un objeto conexión, el cual se puede utilizar para crear un cursor. Un cursor es necesario para ejecutar una sentencia SQL y para recuperar el resultado generado por consultas.

cursor = conexion.cursor()

Recuperación de información: SELECT.

En MySQLdb hay varias formas de recuperar información, dependiendo del método que utilicemos a la hora de recuperar las filas (después de lanzar la sentencia SQL select):

1) Mediante el método fetchall. Mediante este método se nos devuelven todas las filas del resultado de hacer el select. El formato en el que se nos da es una tupla de tuplas, donde cada tupla es una fila del resultado.

Ejecutamos sentencia SQL select:

cursor.execute("SELECT * FROM cliente")

Recuperamos las filas (que están en el servidor) resultado de la sentencia select:

ret = cursor.fetchall()

Y las sacamos por pantalla.

print ret

Dando el siguiente resultado:

((1L, '\xc1ngel', 'Lorca'), (2L, 'H\xe9ctor', 'La Uni\xf3n'), (3L, 'Juan Mar\xeda', 'Los Belones'), (4L, 'Mar\xeda', 'La Uni\xf3n'), (5L, 'Fernando', 'Murcia'), (6L, 'Ana', 'Murcia'), (7L, 'Dori', 'Los Belones'), (8L, 'Emilia', 'El Llano del Beal'), (9L, '\xc1ngel', 'El Estrecho'), (10L, 'Naomi', 'Los Belones'), (11L, '\xc1lvaro', 'Lorca'), (12L, 'Gabriela', 'Barcelona'))

Como vemos, es una tupla de tuplas, es decir, una tupla que contiene un conjunto de tuplas, en donde cada elemento del conjunto es un fila del resultado del select definido en el método execute del cursor. Podemos mejorar la salida:


print "Listado de clientes"
print "-------------------"
for fila in ret:
print str(fila[0]), " - " , str(fila[1]).strip(), " (", str(fila[2]).strip(), ")"

Y para ver la potencialidad que tenemos a la hora de recoger los datos del select, mira el siguiente código:

i = 0
for fila in ret:
for campo in range(0,len(fila)):
print "Dato en coord. (i = ",str(i),", j = ",str(campo),"): ",fila[campo]
i = i + 1


Y el resultado que da:

Posición en coordenadas (i = 0 , j = 0 ): 1
Posición en coordenadas (i = 0 , j = 1 ): Ángel
Posición en coordenadas (i = 0 , j = 2 ): Lorca
Posición en coordenadas (i = 1 , j = 0 ): 2
Posición en coordenadas (i = 1 , j = 1 ): Héctor
Posición en coordenadas (i = 1 , j = 2 ): La Unión
Posición en coordenadas (i = 2 , j = 0 ): 3
Posición en coordenadas (i = 2 , j = 1 ): Juan María
Posición en coordenadas (i = 2 , j = 2 ): Los Belones
Posición en coordenadas (i = 3 , j = 0 ): 4
Posición en coordenadas (i = 3 , j = 1 ): María
Posición en coordenadas (i = 3 , j = 2 ): La Unión
Posición en coordenadas (i = 4 , j = 0 ): 5
Posición en coordenadas (i = 4 , j = 1 ): Fernando
Posición en coordenadas (i = 4 , j = 2 ): Murcia
Posición en coordenadas (i = 5 , j = 0 ): 6
Posición en coordenadas (i = 5 , j = 1 ): Ana
Posición en coordenadas (i = 5 , j = 2 ): Murcia
Posición en coordenadas (i = 6 , j = 0 ): 7
Posición en coordenadas (i = 6 , j = 1 ): Dori
Posición en coordenadas (i = 6 , j = 2 ): Los Belones
Posición en coordenadas (i = 7 , j = 0 ): 8
Posición en coordenadas (i = 7 , j = 1 ): Emilia
Posición en coordenadas (i = 7 , j = 2 ): El Llano del Beal
Posición en coordenadas (i = 8 , j = 0 ): 9
Posición en coordenadas (i = 8 , j = 1 ): Ángel
Posición en coordenadas (i = 8 , j = 2 ): El Estrecho
Posición en coordenadas (i = 9 , j = 0 ): 10
Posición en coordenadas (i = 9 , j = 1 ): Naomi
Posición en coordenadas (i = 9 , j = 2 ): Los Belones
Posición en coordenadas (i = 10 , j = 0 ): 11
Posición en coordenadas (i = 10 , j = 1 ): Álvaro
Posición en coordenadas (i = 10 , j = 2 ): Lorca
Posición en coordenadas (i = 11 , j = 0 ): 12
Posición en coordenadas (i = 11 , j = 1 ): Gabriela
Posición en coordenadas (i = 11 , j = 2 ): Barcelona

Como se puede observar, esto da bastante juego, sobretodo a la hora de presentar la información resultante.

lunes, 8 de febrero de 2010

EDITRA - Un editor para desarrollar en Python

¿Cómo trabajar con Python? Cuando se instala Python lleva consigo IDLE, un GUI para crear aplicaciones Python desde el primer momento. Para aprender Python no está mal, ya que lleva completitud de código (al estilo Visual Basic), detección de errores y demás cosas. Uno de los problemas que tiene esta herramienta es cuando usamos librerías gráficas, como wxPython, donde sencillamente, hay veces, que "casca". wxPython e IDLE no son compatibles.

También se puede optar por el python.exe de toda la vida, un editor de textos y listo. El problema viene después, cuando la aplicación empieza a hacerse grande y más grande. Necesitamos herramientas de edición mas potentes y un simple editor de texto no es suficiente (un editor normal no lleva completitud de código).

La cuestión es que después de estar varios meses viendo en Internet la oferta de editores, IDE's y RAD's disponibles para Python (me los he instalado todos, los he probado todos, me han gustado casi todos), me he decidido por uno, EDITRA, un editor para programadores escrito por Cody Precord.

EDITRA se puede obtener de http://www.editra.org.

La elección de un editor de desarrollo tiene que ver mucho con cada uno, es algo bastante personal. Así, la gente que viene de Unix está más que habituada al Emacs y vi, con lo que este editor quizás no es para ellos. Si se viene del mundo Java, puede ser que NetBeans sea la mejor opción, ya que no es necesaria ninguna adaptabilidad, ya sabe cual es el entorno de desarrollo.

Si lo que estamos buscando es un entorno de desarrollo rápido de aplicaciones, la mejor opción (y la única, porque yo no la he encontrado, y si alguien la encuentra, por favor, decidlo) es Boa Constructor. Si es un IDE potente, Komodo o Wing (¡aunque son de pago!). Si es un editor de texto avanzado, NotePad++. Todo esto son ejemplos, hay muchos más, como SciTE, Minimum Profit, etc.. Evidentemente, para ver comparativas de las bondades de unos y otros haría falta escribir un post solo para ellos, pero no es este el objetivo. Aquí vamos a hablar de EDITRA, de cómo realizar una configuración sencilla para trabajar con Python, ya que este editor soporta una gran variedad de lenguajes.

Si me he decidido por EDITRA (escrito 100% en Python) es porque tiene todo lo que quiero y necesito (¡¡¡esto no quiere decir que sea lo que quieran los demás, claro!!!). Lo primero y muy importante es que es gratuito. Lo segundo y fundamental, está en español (y no es que tenga algo en contra del inglés, en absoluto, lo leo perfectamente, pero da gusto, después de tanto tiempo trabajando en PowerBuilder, un entorno de desarrollo en el lenguaje patrio). Como características técnicas, tiene todo lo que se necesita para programar, a saber: indentación de código, completitud de código Python, ejecución de la aplicación, compatible con wxPython, plugins para Python descargables, y mega configurable, ademas de las características propias de cualquier editor, como la búsqueda, reemplazo. Y mucho más, como se verá.

EDITRA es un proyecto que se encuentra en fases tempranas de desarrollo (de echo, la última versión a la hora de escribir este post es la 0.5.32). Cada nueva versión tiene nuevas y mejoradas características, las cuales pueden ser totalmente configuradas por el usuario. Es más, la práctica totalidad de las características de EDITRA son configurables, con lo que podemos personalizar al máximo nuestro entorno de trabajo. Y es aquí donde vamos a hablar, de su configuración personalizada.

Para ver esta configuración lo que he hecho ha sido capturar pantallas, de manera que voy mostrando lo que he activado de las múltiples opciones que lleva esta aplicación. Las mas importantes las comento, otras no es necesario, ya que se ven en la captura correspondiente.

Una vez descargado e instalado nos aparece tal que así:

Como hemos comentado anteriormente, EDITRA es un editor multilenguaje. Es por ello que lo primero que hacemos es decirle que vamos a programar en Python, en Preferencias/Analizadores léxicos.

Podemos configurar la apariencia gráfica (el estilo) de la sintaxis del lenguaje, esto es, colores, tipos de letra, según el código que vamos escribiendo. Hay temas de estilo ya creados, aunque podemos crear los propios. Se configura como se ve en la captura de pantalla:














A mi personalmente me gusta el estilo Cream.

Por el momento le hemos dicho a EDITRA lo que queremos y cómo queremos que nos lo muestre (lo básico). Ahora toca decirle qué queremos cada vez que se inicie la aplicación, quienes somos y de donde venimos. Para ello nos vamos a Preferencias. En General, le indicamos que queremos hablar español













En Documento/General podemos configurar el tipo de letra que queremos para escribir. Y algo muy importante, podemos configurar el tabulador para la indentación de código (a mi personalmente, más de 4 me parece excesivo). En Documento/Código le decimos que queremos que siempre que se abra EDITRA se analice la sintaxis de Python (esto me ha gustado mucho). Darse cuenta de la activación de la ayuda del autocompletado.














Para los usuarios que vengan del mundo de Visual Studio de Microsoft, están de enhorabuena (yo que estuve algunos años programando en Visual Basic 6), ya que EDITRA lleva configurado atajos de teclado al estilo de esta herramienta. Esto es:

Algo que me obsesionaba a la hora de elegir un editor para programar en Python era la completitud de código, que la tuviera y que fuera rápida. En IDLE la hay, pero es bastante lenta (¡para mi entre 1 y 2 segundos es lento!). En EDITRA esto va bastante bien. Haz la prueba.

Llegados a este punto vamos a incluir dos características, que en principio están desactivadas en EDITRA. La primera es la activación del Lanzador (Launch), que nos servirá para ejecutar nuestros scripts Python. La segunda es la activación del navegador de código (Code Browser), que nos permitirá navegar a través de nuestra aplicación (esto me ha gustado muchísimo). Para ello nos vamos al gestor de plugins:














Una vez hemos activado Launch, vemos que aparecen en Herramientas 2 opciones para ejecutar código. Para mostrar el lanzador (el que ejecutará el script Python) hay que decírselo a EDITRA, en Ver/Estante/Launch.















NOTA IMPORTANTE: Un punto negativo es que para que el lanzador funcione tiene que estar el fichero de código guardado previamente, de lo contrario no se activa la opción de Ejecutar. Primero se crea el código, se guarda en un fichero, mostramos Launch y entonces nos deja Ejecutar.















Si hacemos click en el icono de herramientas de Launch (esquina superior izquierda del Shelf) podemos configurar el lanzamiento de la aplicación. Para explorar el código y poder navegar a través de él (una vez activado el plugin) hay que decírselo a EDITRA. Lo hacemos y lo probamos:















Darse cuenta lo fácil que es navegar por el desarrollo ahora. Haciendo doble click sobre cualquier elemento del navegador nos lleva directamente al código.

Cosas que no me terminan de convencer. Hay 2. En primer lugar, Launch no permite datos de entrada, solo sirve para datos de salida (print y cosas por el estilo). Así, si tenemos que incluir datos por consola en nuestro script, dará error. Por ejemplo:

Este script en principio debería de funcionar, pero Launch no permite la entrada de datos. Es más, si ejecutamos este fichero en una consola de siempre (cmd.exe) funciona:














En segundo lugar hay un plugin, que nos dice la aplicación podemos descargar, llamado IPyShell, un shell de Python interactivo, que en teoría serviría (creo, no lo sé) para solventar el problema de scripts que piden información por consola. Lo he intentado instalar, pero no sale nada. Lo más seguro es que sea culpa mía. Seguiré investigando. En la web de EDITRA nos da una captura de pantalla, indicando como funciona:

Como una última reseña una funcionalidad que me recuerda a mis días en PowerBuilder, y es que podemos, mediane el uso del ratón, comentar y descomentar regiones de código (esto también me ha gustado bastante). Lo único que hay que hacer es seleccionar el trozo de código que queramos comentar e ir a la opción de poner comentario. Para descomentar, lo mismo, seleccionar y hacer click en la misma opción, tal que así:













CONCLUSIONES

EDITRA es un editor avanzado para desarrollo, para programadores. Escrito totalmente en Python, a primera vista vemos que da todas las facilidades para desarrollar en este lenguaje. Hiper configurable, para todos los gustos y colores. Hay mejores en el mercado, en cierta manera justificado por la temprana edad de este producto y por las empresas grandes que desarrollan productos para uso de Python (ActiveState, Sun, etc.).

Para programar en Python EDITRA tiene las cualidades que se buscan, esto es, indentación y completitud de código, ayuda, sintaxis, en español y gratuito.

Hay algo en este editor que lo hace diferente. Quizás el espíritu pythónico que lo envuelve.