SlideShare una empresa de Scribd logo
1 de 84
Descargar para leer sin conexión
W W W . L I N U X - M A G A Z I N E . E S
8413042594529
00006
BÁSICO
Introducción a
Python con
ejemplos prácticos
Denis Babenko - 123RF.com
MANUAL PRÁCTICO
DVD GRATIS
Debian 6
17PROYECTOS COMPLETOS
Y FUNCIONALES
Tu Guía Práctica
Aprende de desarrolladores
profesionales y de sus
ejemplos del mundo real
■ Automatiza formularios web
■ Integra Python con Java, .Net y Qt
■ Amplía Open/LibreOffice
■ Crea y manipula PDFs
■ Maneja grandes volúmenes de datos
ENERO 2012
Península y Baleares 6,95 €
Canarias 7,05 €
Especial
06
INFRAESTRUCTURAS
Explota los motores tras
Facebook, Google y Twitter
48
MÓDULOS
Descubre cómo programar
para 3D y a manipular datos
e imágenes
59
En la tienda de Linux Magazine (www.linux-magazine.es/tienda) vendemos revistas y libros que pue-
den ser de interés a nuestros lectores. Recuerda también que con una subscripción Digital o Club,
podrás acceder a las ofertas (www.linux-magazine.es/digital/ofertas) de Linux Magazine donde pue-
des conseguir software, gadgets, libros y servicios. Este mes en nuestra tienda...
Manual LPIC-1
El único manual en castellano para la certificación com-
pleta LPIC-1 (exámenes 101 y 102). Más de 250 páginas
de ejemplos reales tomados de ambos exámenes expli-
cados en todo detalle con ejercicios para prácticas y sus
soluciones.
Preparado para el nuevo programa que entra en vigor a
partir del 2009, aprobado y recomendado por LPI Inter-
national y con la garantía de Linux Magazine.
■ ”La guía perfecta en castellano para preparar el exa-
men para cualquier persona que tenga conocimien-
tos de Linux.”
■ ”Se ciñe muy bien a los objetivos del nivel 1 de LPI
(LPIC-1) actualizados en Abril de este año, cosa que
es de agradecer.”
■ ”Un avance muy importante en el desarrollo de los
programas de certificación LPI en España.”
www.lpi.org.es
Consíguelo en nuestra tienda.
DVD/EDITORIALDebian 6
3PYTHONWWW.LINUX- MAGAZINE.ES
Especial Python
En el DVD de este especial encontrarás
la versión Live de la última iteración
estable de Debian [2] para arquitecturas
de 32 bits (la más universal). Al ser
Debian la más completa de las distros
GNU/Linux, podrás encontrar en sus
repositorios todas las herramientas,
módulos e infraestructuras que necesita-
rás para seguir los artículos de este
especial.
DVD: Debian 6.0.3
Aunque la norma en el sangrado de
código en Python es que las tabulaciones
a principio de línea sean múltiplos de cua-
tro espacios, para favorecer la legibilidad
de los listados en este especial, cada tabu-
lación se ha reducido a un solo espacio.
De esta manera, código que normal-
mente se escribiría como:
for i in range (1, 5):
if ((i % 2) == 0):
print i,” es par”
else:
print i,” es impar”
Se reproduce así en los artículos:
for i in range (1, 5):
if ((i % 2) == 0):
print i,” es par”
else:
print i,” es impar”
A pesar de ser técnicamente correcto,
animamos a que, si se transcribe código
para su ejecución, se utilice la conven-
ción de los 4 espacios.
En todo caso, todo el código está dispo-
nible, con su formato convencional, en el
sitio de Linux Magazine en [1].
Formato del Código en este Especial
[1] Todo el código de este especial: http://
www.linux-magazine.es/Magazine/
Downloads/Especiales/06_Python
[2] Debian: http://www.debian.org/index.
es.html
Recursos
Bautizado en honor al grupo de cómicos británicos Monty
Python, Guido Von Rossum concibió este lenguaje en los
años 80, comenzando su implementación en 1989. Gra-
cias a su sencillez y a la idea de que el código bello se
consigue siendo explícito y simple, Python se ha
convertido en sus poco más de 20 años de exis-
tencia en el lenguaje favorito para scripts, aun-
que también para grandes infraestructuras y
aplicaciones.
Así, la mayor parte de los servicios de Goo-
gle y Facebook se construyeron utilizando
Python, las aplicaciones de diseño Inkscape
o Blender (entre muchas otras) utilizan un
motor Python para sus plugins. También se
utiliza ampliamente en la investigación en
entidades que van desde CERN hasta la
NASA.
Además, su clara y bien pensada sintaxis,
su modularidad y su sobresaliente rendi-
miento – a pesar de ser interpretado – hacen de
Python un excelente lenguaje educativo, ideal
para enseñar programación del mundo real a todos
los niveles.
Con este especial pretendemos que el lector pueda
descubrir Python desde el principio, creando para ello
artículos que abordan desde tutoriales introductorios, hasta
programación de alto nivel y para usos avanzados. Cada sección
viene con varios ejemplos prácticos, código y soluciones extraídas del
mundo real. ■
CONTENIDO Python 01
4 PYTHON WWW.LINUX- MAGAZINE.ES
06 Primeros Pasos
Python es un lenguaje potente,
seguro, flexible… pero sobre todo sen-
cillo y rápido de aprender, que nos
permite crear todo lo que necesitamos
en nuestras aplicaciones de forma ágil
y eficaz
10 Álbum Fotográfico
Siguiendo con nuestro paseo por
Python, vemos características básicas,
y concretamente en este artículo, el
tratamiento de ficheros creando un
programa para la ordenación de colec-
ciones de fotos.
15 Desparasitando Serpientes
Da igual lo buenos programadores
que seamos, tarde o temprano dare-
mos con ese BUG que será nuestro
peor enemigo. Veamos cómo pode-
mos emplear herramientas para derro-
tarlo con mayor facilidad.
19 Sin Nombre
Python es un lenguaje de programa-
ción multiparadigma, y las funciones
lambda son parte fundamental de él,
aunque como veremos, existen bue-
nas razones para no abusar de ellas.
23 Python no hay más que UNO
¿Has visto alguna vez a los brokers de
bolsa y sus sofisticados y caros pro-
gramas para ver las cotizaciones de
las empresas en bolsa en tiempo real?
Nosotros haremos lo mismo con
Python, OpenOffice y la tecnología
UNO de OpenOffice.
28 Cuando los Mundos Chocan
Os descubrimos Jython, la forma mas
sencilla de desarrollar vuestras aplica-
ciones Java como si las programárais
con Python.
33 Limpieza Total
AJAX es la palabra de moda, Google
usa AJAX, Yahoo usa AJAX… todo el
mundo quiere usar AJAX pero ¿lo
usas tú? y más importante aún ¿qué
demonios es AJAX?
39 De Serpientes y Primates
.NET está avanzando, y Python no se
ha quedado atrás. En lugar de comba-
tirlo, ha entrado en simbiosis con ella.
Con Ironpython podremos hacer uso
de toda la potencia de .NET desde
nuestro lenguaje favorito.
43 ¡Desarrollo Rápido!
Ha llegado el cliente y te lo ha dejado
claro: necesita el programa para ayer.
Ha surgido un problema enorme y es
necesario resolverlo en tiempo récord.
La desesperación se palpa en el
ambiente y todos los ojos miran a tu
persona. Devuelves una mirada de
confianza y dices con tono tranquilo:
«No te preocupes, tengo un arma
secreta para acabar con el problema».
03 DVD Debian 6
82 Información de Contacto
Otras Secciones
Introducción Avanzado
Integración
Integración
CONTENIDOPython 01
5PYTHONWWW.LINUX- MAGAZINE.ES
48 Pyramid
Uno de los rivales de peso de Django
está creciendo en popularidad poco a
poco.
52 Guitarrazos
Los creadores del proyecto Django nos
hablan de la formación de la Django
Software Foundation y mostramos
cómo comenzar con esta infraestruc-
tura web.
55 Seriales
Hacer que distintos servicios se comu-
niquen entre ellos es todo un pro-
blema que Facebook ha tratado de
solucionar con Thrift.
59 Cuaderno de Bitácora
¿Te acuerdas de cuando cambiaste la
versión de Firefox por última vez? ¿ y
de por qué instalaste ese programa tan
raro que parece no servir para nada ?
Yo tengo mala memoria, así que uso
un cuaderno de bitácora.
65 Gráficas 3D
Crear gráficos 3D no es nada difícil en
Python... sobre todo si tenemos a
mano la librería VTK.
69 Vigilantes del planeta
¿Quién no ha querido alguna vez sen-
tirse como esos informáticos de la
NASA en su centro de control? Hoy
nos construiremos el nuestro y contro-
laremos el planeta y sus alrededores.
73 Enredados
Podemos automatizar comandos y
programas gráficos, ¿por qué no auto-
matizar la interacción con páginas
web? En este artículo crearemos un
pequeño script que puede ahorrarnos
mucho trabajo con el ratón.
77 ReportLab
Hoy en día se hace imprescindible dis-
poner de herramientas que permitan
generar informes en PDF de alta cali-
dad rápida y dinámicamente. Existen
diferentes herramientas para esta fina-
lidad, entre ellas cabe destacar Repor-
tLab, biblioteca gratuita que permite
crear documentos PDF empleando
como lenguaje de programación
Python.
Ver información en pág. 3
VERSIÓN
DVDGNOME LIVE
Infraesctructuras
Librerías
Librerías
INTRODUCCIÓN Primeros Pasos
6 PYTHON WWW.LINUX- MAGAZINE.ES
Para empezar, debemos saber por qué
Python es interesante, por qué es tan
famoso y cada vez más utilizado. Mirando
un poco por Internet se pueden encontrar
multitud de aplicaciones que nos muestran
parte de las capacidades de este lenguaje
de alto nivel. Vamos a enumerar algunas
de sus sorprendentes características:
• Orientado a objetos – Esto no significa
que sea exclusivamente orientado a
objetos, podemos utilizarlo como quera-
mos, aunque le sacaremos más prove-
cho si usamos su implementación de
OOP (Programación Orientada a Obje-
tos).
• Libre y gratuito – Desde la red, pode-
mos descargar el interprete y su código
fuente, y al ser un lenguaje de script,
viene con la mayoría de las distros
GNU/Linux de manera predeterminada,
siendo posible ver el código de una
enorme parte del software desarrollado
para Python.
• Portable – Al ser interpretado, podemos
ejecutar nuestros programas en cual-
quier S.O. y/o arquitectura simplemente
teniendo instalado previamente el intér-
prete en nuestro ordenador .
• Potente – Realizar un programa bajo
este lenguaje seguramente nos costaría
entre la mitad o la cuarta parte del
tiempo que tardaríamos en desarrollar el
mismo programa en C/C++ o Java.
• Claro – Puede que ésta sea una de las
características más alabadas de Python:
Los programas escritos en este lenguaje
tienden a ser fáciles de comprender y,
por tanto, de mantener por terceros. Una
enorme ventaja frente a lenguajes como
C o Perl.
Pero veamos una breve comparativa con
otros lenguajes:
Hola Mundo en C:
main ()
{
printf(“Hola Mundo”);
}
Hola Mundo en Java:
public static void U
main(String args[])
{
System.out.println(“Hola U
Mundo”);
}
Hola Mundo en Python:
print “Hola Mundo”
Aunque los “Hola Mundo” no son muy
indicativos de nada, nótese la ausencia de
puntos y comas, llaves, declaración de fun-
ciones y otros “trastos” que entorpecen el
código. Esto es incluso más obvio en pro-
gramas más largos.
Python dispone de otras características
que lo convierten en el lenguaje favorito
de una comunidad de desarrolladores
cada vez más amplia. Por ejemplo, per-
mite la declaración dinámica de varia-
bles, es decir, no tenemos que declarar
las variables ni tener en cuenta su
tamaño, ya que son completamente diná-
micas. Además, dispone de un gestor de
memoria que, de manera similar al de
java, se encargará de liberar memoria de
objetos no utilizados. Sin embargo, y al
igual que Java, no permite usar la memo-
ria a bajo nivel como C, con el que nos
podíamos referir a zonas de memoria
directamente.
Además se puede combinar con otros
múltiples lenguajes de programación.
Podemos mezclar en nuestras aplicaciones
Python y Java (Jython – ver el artículo al
respecto en la página 28 de este especial),
por ejemplo. O Python con C/C++, lo
cual hace que resulte mas potente si cabe.
Python también cuenta con una amplia
biblioteca de módulos que, al estilo de las
bibliotecas en C, permiten un desarrollo
rápido y eficiente.
La sencillez de Python también ayuda a
que los programas escritos en este lenguaje
sean muy sintéticos. Como podemos ver
en el ejemplo “Hola Mundo” anterior, la
simplicidad llega a ser asombrosa. Si este
programa ya supone ahorrarte 4 ó 5 líneas
de código, con una sintaxis tan sencilla y
ordenada podemos imaginar que un pro-
grama de 1000 líneas en Java, en Python se
redujeran unas 250.
Python es un lenguaje potente, seguro, flexi-
ble… pero sobre todo sencillo y rápido de
aprender, que nos permite crear todo lo que
necesitamos en nuestras aplicaciones de
forma ágil y eficaz. Por José María Ruíz
Aprende a programar con este lenguaje de programación multiplataforma
Primeros Pasos
AnitaPatterson-morguefile.com
Uso
Para empezar a matar el gusanillo, pode-
mos ir haciendo algunas pruebas intere-
santes. Vayamos al intérprete Python. Para
ello, basta con escribir ‘python’ en el
prompt de una terminal (por ejemplo,
Bash en GNU/Linux o Powershell en Win-
dows) y probar nuestro “Hola Mundo”:
>>> print ‘Hola Mundo’
Hola Mundo
Ahora probemos a utilizar algunas varia-
bles:
>>> suma = 15 + 16
>>>
>>> print ‘el resultado de la U
suma es: ‘, suma
el resultado de la suma es: 31
Es recomendable trastear un poco con esto
antes de ponernos a programar algo más
complicado, ya que de esta manera es más
sencillo hacerse con la sintaxis mucho más
rápidamente viendo los resultados de cada
prueba.
Veamos ahora alguna propiedad intere-
sante de Python. Los ficheros en Python
no tienen por qué llevar extensión nin-
guna, pero seguramente querremos tener-
los diferenciados del resto de ficheros que
tengamos. Por ello se suele utilizar la
extensión .py.
Pero ¿cómo sabe el sistema que intér-
prete utilizar cuando queramos ejecutar
nuestros scripts? Sencillo: Imaginemos que
tenemos un ejemplo.py, al ser un lenguaje
tipo script, debemos poner #! seguido de la
ruta del intérprete de Python en la cabe-
cera del fichero. De esta manera, y dándole
permisos de ejecución (chmod +x ejem-
plo.py en GNU/Linux), obtenemos un pro-
grama listo para su ejecución.
Si nuestro intérprete Python se halla en
/usr/bin/, el contenido de ./ejemplo.py
quedaría, pues, como sigue:
#! /usr/bin/python
print ‘Hola Mundo’
Después de toda la introducción técnica va
siendo hora de que veamos cómo es el for-
mato de los programas en Python. Esto es
importante porque, mientras la norma en
la mayoría de los lenguajes es dejar al pro-
gramador la decisión de la manera en que
deben ser formateados los archivos fuente,
en Python es obligatorio hacerlo de cierta
forma. En Python todo se hace de un solo
modo, de hecho es parte de su filosofía:
“Solo Hay Una Manera de Hacer Las
Cosas”.
Comencemos con lo más simple en todo
lenguaje, la asignación a una variable:
cantidad = 166.386
(Para los que no lo recuerden, 166,386 era
la cantidad de pesetas que hay en un euro).
Lo primero que hay que apreciar es que
no se usa el ;. Esto es una característica de
las muchas que hacen a Python diferente.
Una sentencia acaba con el retorno de
carro, aunque el ; se puede usar cuando
dos sentencias están en la misma línea:
cant = 166.386; ptas = 3000
Como es un lenguaje dinámico, no hay
que declarar el tipo de las variables, pero
una vez que una variable ha sido definida
(lo que se hace asignándole un valor), esa
variable guarda su tipo y no lo cambiará a
lo largo de la ejecución del programa.
También tenemos a nuestra disposición
los operadores habituales de otros lengua-
jes: +, -, *, /, etc. Y una vez que sabemos
cómo manejar operadores y asignaciones,
se pueden hacer cosas útiles, pero sólo de
manera lineal. Para que la ejecución no sea
lineal necesitamos los bucles y los condi-
cionales.
El tema de los bucles en Python es algo
especial. Puede que estemos acostumbra-
dos a los que son de tipo C:
for (a = 1; a < 10; a++) U
printf(“%dn”,a);
Sin embargo, en Python se toma un enfo-
que funcional prestado de otros lenguajes
como Lisp o Haskell. Se utiliza una fun-
ción especial llamada «range». La función
«range» genera una lista de números:
range(1,10)
generará una ristra de números del 1 al 9.
De esta manera, podemos utilizar una fun-
ción range para crear un bucle for en
Python de la siguiente manera:
for i in range(1,10)
Este bucle iteraría con i desde 1 a 9, ambos
inclusive. La versión del bucle while en
Python es más normal…
while(<condición>)
al igual que if…
if (<condición>)
¿Por qué no he puesto cuerpos de ejemplo
en esos bucles? Pues porque ahora viene
otra novedad. En Python no se usan las
famosas { y } para delimitirlas. Se decidió
(y no a todo el mundo le gusta) que se usa-
ría la posición como delimitador. Esto, así,
suena algo extraño, pero si se ve es mucho
más sencillo:
>>> cantidad = 2
>>> for i in range(1,10):
print cantidad*i
Comencemos mirando a ese :. Los dos
puntos marcan el inicio de un bloque de
código Python. Ese bloque aparecerá en
bucles, funciones o métodos. Si nos fija-
mos bien en la sangría de la siguiente
línea, vemos una serie de espacios (logra-
dos pulsando la tecla TABULADOR) y una
sentencia. Esos espacios son vitales, ya
que marcan la existencia de un bloque de
código. Además, son obligatorios.
Este es uno de los hechos más contro-
vertidos de Python, pero también mejora
mucho la legibilidad del código. Sólo existe
una manera de escribir Python, así que
todo el código Python se parece y es más
fácil de entender. El bloque acaba cuando
desaparecen esos espacios:
>>> for i in range(1,10):
... print cantidad*i
... cantidad = cantidad + 1
...
>>>
Funciones y Objetos
Ya tenemos las piezas fundamentales para
entender las funciones y los objetos. La
declaración de una función en Python
tiene una sintaxis muy simple:
def nombre_funcion U
(<lista argumentos>):
<CUERPO>
Fácil ¿no? Al igual que las variables, a los
argumentos no se les asignan tipos. Exis-
ten muchas posibilidades en los argumen-
tos, pero los veremos más tarde. De
momento examinemos un ejemplo sim-
ple:
INTRODUCCIÓNPrimeros Pasos
7PYTHONWWW.LINUX- MAGAZINE.ES W W W. L I N U X - M A G A Z I N E . E S
Estructuras de Datos
Una de las razones por las que los progra-
mas scripts de Python resultan tan poten-
tes, es que nos permiten manejar estructu-
ras de datos muy versátiles de manera
muy sencilla. En Python estas estructuras
son las Listas y los Diccionarios (también
llamados Tablas Hash).
Las listas nos permiten almacenar una
cantidad ilimitada de elementos del mismo
tipo. Esto es algo inherente a casi todos los
programas, así que Python las incorpora
de fábrica. Las listas de Python también
vienen provistas de muchas más opciones
que sus semejantes en otros lenguajes. Por
ejemplo, vamos a definir una lista que
guarde una serie de palabras:
>>> a = [“Hola”, “Adios”, U
“Buenas Tardes”]
>>> a
[‘Hola’, ‘Adios’, U
‘Buenas Tardes’]
Python indexa comenzando desde 0, de
manera que ‘Hola’ es el elemento 0, ‘Adios’
el 1 y ‘Buenas Tardes’ el 2, y la longitud de
la lista es 3. Podemos comprobarlo de esta
forma:
>>> a[1]
‘Adios’
>>> len(a)
3
Es posible añadir elementos a las listas de
varias maneras. Si miramos el Listado 2,
veremos la más sencilla. Las listas también
se pueden comportar como una Pila, con
las operaciones append y pop. Con insert
introducimos un elemento en la posición
especificada (recuerda que siempre
comenzamos a contar desde 0). La facili-
dad con la que Python trata las listas nos
permite usarlas para multitud de tareas, lo
que simplificará mucho nuestro trabajo.
A pesar de su potencia, las listas no pue-
den hacerlo todo, existiendo otra estruc-
tura que rivaliza con ellas en utilidad, los
Diccionarios. Mientras las listas nos permi-
ten referenciar a un elemento usando un
número, los diccionarios nos permiten
hacerlo con cualquier otro tipo de dato.
Por ejemplo, con cadenas, de hecho, casi
siempre con cadenas, de ahí que su nom-
bre sea diccionario (véase el Listado 3).
Las listas y los diccionarios se pueden
mezclar: diccionarios de listas, listas de
diccionarios, diccionarios de listas de dic-
cionarios, etc. Ambas estructuras combi-
nadas poseen una enorme potencia.
Algoritmos + Estructuras de Datos
= Programas
Ahora nos toca poner todo esto en prác-
tica. Lo normal es hacer un programa sen-
cillo. Pero en lugar de eso vamos a imple-
mentar algo que sea creativo. Este pro-
grama es el que se usa en el libro “La prác-
tica de la programación” de Pike y Kernig-
han para ilustrar cómo un buen diseño
sobrepasa al lenguaje que usemos para eje-
>>> def imprime (texto):
... print texto
>>> imprime(“Hola mundo”)
Hola mundo
>>>
Vuelve a ser sencillo. ¿Y los objetos? Pues
también son bastante simples de imple-
mentar. Podemos ver un ejemplo en el Lis-
tado 1. Con class declaramos el nombre de
la clase, y los def de su interior son los
métodos. El método __init__ es el cons-
tructor, donde se asignan los valores inicia-
les a las variables. __init__ es un método
estándar y predefinido, lo que quiere decir
que tendremos que usar ése y no otro para
inicializar el objeto. Todos los métodos,
aunque no acepten valores, poseen un
parámetro self. Este es otro punto contro-
vertido en Python; self es obligatorio, pero
no se usa al invocar el método. ¿Cómo se
crea el objeto?
>>> a = Objeto(20)
Es como llamar a una función. A partir de
este momento a es una instancia de
Objeto, y podemos utilizar sus métodos:
>>> print a.getCantidad()
20
>>> a.setCantidad(12)
>>> print a.getCantidad()
12
No hay que preocuparse por la administra-
ción de la memoria del objeto ya que,
cuando a no apunte al objeto, el gestor de
memoria liberará su memoria.
Ya tenemos las bases para construir algo
interesante. Por supuesto, nos dejamos
infinidad de cosas en el tintero, pero siem-
pre es mejor comenzar con un pequeño
conjunto de herramientas para empezar a
usarlas. En todo caso, tendremos tiempo
de profundizar en los siguientes artículos
de este especial.
INTRODUCCIÓN Primeros Pasos
8 PYTHON WWW.LINUX- MAGAZINE.ES
01 class Objeto:
02 def __init__ (self, cantidad):
03 self.cantidad = cantidad
04
05 def getCantidad(self):
06 return self.cantidad
07
08 def setCantidad(self,
cantidad):
09 self.cantidad = cantidad
Listado 1: Una Clase Sencilla
01 >>> dic = {}
02 >>> dic[“Perro”] = “hace guau
guau”
03 >>> dic[“Gato”] = “hace miau
miau”
04 >>> dic[“Pollito”] = “hace pio
pio”
05 >>> dic
06 {‘Perro’: ‘hace guau guau’,
07 ‘Gato’: ‘hace miau miau’,
08 ‘Pollito’: ‘hace pio pio’}
09 >>> dic[“Perro”]
10 ‘hace guau guau’
Listado 3: Ejemplo Diccionario
01 >>> b = [ 1 , 2 , 1 ]
02 >>> b.append(3)
03 >>> b.append(4)
04 >>> b
05 [1 , 2 , 1 , 3 , 4 ]
06 >>> b.remove(1)
07 >>> b
08 [2, 1, 3, 4]
09 >>> b.pop()
10 4
11 >>> b
12 [2, 1, 3]
13 >>> b.insert(1,57)
14 >>> b
15 [2, 57, 1, 3]
16 >>> b.append(1)
17 >>> b
18 [2, 57, 1, 3, 1]
19 >>> b.count(1)
20 2
21 >>> b.index(57)
22 1
23 >>> b.sort()
24 >>> b
25 [1, 1, 2, 3, 57]
26 >>> b.reverse()
27 >>> b
28 [57, 3, 2, 1, 1]
Listado 2: Adición y Eliminación de Elementos de Lista
cutarlo. En el libro se implementa el diseño
en C, C++, Java, Perl y AWK. Nosotros lo
haremos en Python (ver Listado 4).
El programa acepta un texto como
entrada y genera un texto como salida, pero
este segundo texto no tiene sentido. Lo que
queremos hacer es generar texto sin sentido
pero con estructuras que sí lo tengan. Puede
parecer algo muy complicado, pero no lo es
tanto si usamos la técnica de cadenas de
Markov. La idea es coger 2 palabras, elegir
una palabra que suceda a cualquiera de las
dos y reemplazar la primera por la segunda
y la segunda por la palabra escogida. De
esta manera vamos generando un texto que,
aunque carece de sentido, normalmente se
corresponde con la estructura de un texto
normal aunque disparatado.
Para hacer las pruebas es recomendable
conseguir un texto de gran tamaño. En tex-
tos pequeños no surtirá tanto efecto. En el
proyecto Gütenberg podemos conseguir
infinidad de textos clásicos de enorme
tamaño en ASCII. Pero somos conocedores
de que no todo el mundo entiende el
idioma anglosajón, así que en lugar de ir al
proyecto Gütenberg, podemos coger cual-
quier texto que queramos modificar, por
ejemplo, alguna noticia de política de un
diario digital o alguna parrafada de algún
blog.
Este programa es interesante porque per-
mitirá utilizar las estructuras de datos que
Python implementa, en particular en los
diccionarios, que generan una tabla donde
los índices serán cadenas de texto.
Veamos cómo funciona. Lo primero es ir
introduciendo en el diccionario dos prefi-
jos como índice y las palabras que les
siguen en el texto dentro de una lista refe-
renciada por ellos. Eso es un diccionario
con dos palabras como índice que contiene
una lista:
DICCIONARIO[ palabra 1, U
palabra 2] -> U
LISTA[palabra,...]
O sea, si tenemos las palabras “La gente
está … La gente opina”, crearemos un dic-
cionario de la siguiente forma:
>>> dict[‘La’, ‘gente’] = U
[‘está’]
>>> dict[‘La’, ‘gente’].U
append(‘opina’)
>>> dict[‘La’, ‘gente’]
[‘está’,’opina’]
Vamos haciendo esto de manera sucesiva
con todos los conjuntos de dos palabras, y
obtendremos un diccionario en el que
muchas entradas referenciarán a una lista
de más de un elemento.
La magia aparece cuando generamos el
texto, puesto que lo que hacemos es
comenzar por las dos primeras palabras, y
cuando existan varias posibilidades para
esa combinación (como con el ejemplo de
‘La’,’gente’), escogeremos aleatoriamente
entre ellas. Imaginemos que escogemos
‘opina’, entonces escribimos ‘opina’ por la
pantalla y buscamos en ‘gente’, ‘opina’ y
así sucesivamente, hasta llegar a no_pala-
bra.
Para entender mejor el funcionamiento
del programa recomendamos copiar el
código fuente y pasarle unos ejemplos
(pongamos, con cat texto.txt |
./markov.py) y ver los resultados. En el
Listado 4 vemos un ejemplo de la salida
utilizando el texto de este artículo. El texto
generado casi tiene sentido, pero no del
todo.
Después podemos intentar cambiar
cosas en el programa, por ejemplo, en
lugar de utilizar 2 palabras como índice del
diccionario, podemos probar con 1 o con
3, y también con el tamaño del texto que
se le pase. Se pueden conseguir cosas muy
interesantes. ■
INTRODUCCIÓNPrimeros Pasos
9PYTHONWWW.LINUX- MAGAZINE.ES
[1] Python: http://www.python.org
Recursos
01 #!/usr/local/bin/python
02
03 #Importamos dos módulos
04 #random [que hace]
05 #y sys [que hace]
06 import random
07 import sys
08
09 no_palabra = “n”
10 w1 = no_palabra
11 w2 = no_palabra
12
13 # GENERAMOS EL DICCIONARIO
14 dict = {}
15
16 for linea in sys.stdin:
17 for palabra in linea.split():
18 dict.setdefault( (w1, w2), []
).append(palabra)
19 w1 = w2
20 w2 = palabra
21
22 # Fin de archivo
23 dict.setdefault((w1, w2), []
).append(no_palabra)
24
25 # GENERAMOS LA SALIDA
26 w1 = no_palabra
27 w2 = no_palabra
28
29 # puedes modificarlo
30 max_palabras = 10000
31
32 for i in xrange(max_palabras):
33 nueva_palabra =
random.choice(dict[(w1, w2)])
34
35 if nueva_palabra == no_palabra:
36 sys.exit()
37
38 print nueva_palabra;
39
40 w1 = w2
41 w2 = nueva_palabra
Listado 4: markov.py Genera un Texto No-Tan-Aleatorio
Para empezar, debemos saber por qué Python es obligatorio hacerlo de una
manera. Como es un lenguaje tipo script, debemos poner ‘#!’ seguido de la
ejecución del programa. También tenemos a nuestra disposición los operadores
habituales de otros lenguajes: +, -, *, /, etc. Y una vez que sabemos cómo
manejar operadores y asignaciones, se pueden mezclar: diccionarios de listas
de diccionarios, diccionarios de listas, listas de Python también vienen
provistas de muchas más opciones que sus semejantes en otros lenguajes. Por
ejemplo, vamos a definir una lista que guarde una serie de espacios (logrados
pulsando la tecla TABULADOR) y una sentencia. Esos espacios son vitales, ya
que marcan la existencia de un texto que, aunque carece de sentido,
normalmente se corresponde con la que Python trata las listas de
diccionarios, diccionarios de listas, listas de Python resultan tan
potentes, es que nos permiten referenciar a un elemento en la sangría de la
OOP. - Es potente. Realizar un programa de 1000 lineas en Java, en Python es
obligatorio hacerlo de una manera. Como es un diccionario con dos palabras
como índice y las palabras que les siguen en el que muchas entradas
referenciarán a una lista de más de un bloque de código Python. Ese bloque
aparecerá en bucles, funciones o métodos. Si nos fijamos bien en la sangría de
la memoria a bajo nivel como C con el tamaño del texto que se usa en el Listado
1.
Listado 5: Salida de markov.py
INTRODUCCIÓN Ficheros
10 PYTHON WWW.LINUX- MAGAZINE.ES
En nuestro primer artículo vimos algo
sobre cómo trabajar con objetos en
Python. Fue muy simple, pero ya nos
daba la posibilidad de organizar nuestro
código en torno a ellos. Python hace un
uso extensivo de los objetos en sus APIs,
y especialmente del control de errores
mediante excepciones, lo que nos da la
opción de lanzarlas cuando algo va mal.
Una excepción es un mensaje que pode-
mos capturar cuando se ejecuta cierta
función o método y aparece un error de
algún tipo. Normalmente controlamos
estos errores mediante el valor devuelto
por la función (como por ejemplo en C).
Esta técnica es engorrosa, pero al igual
que todo, tiene sus virtudes y sus des-
ventajas. Pero Python hace uso de las
excepciones en su lugar.
Cuando una función genera una
excepción, decimos que eleva una excep-
ción. Es muy normal tener que controlar
las excepciones en las operaciones que
realicemos con recursos que pueden no
estar disponibles. Por eso las vamos a
ver, puesto que aquí vamos a trabajar
con archivos y conexiones a Internet.
Crearemos un objeto que gestione un
recurso que puede no estar disponible.
En este caso el objeto gestiona una varia-
ble (véase el Listado 1).
Alguien puede crear un objeto de la
clase obj_variable y llamar al método
set_variable(23), pero ¿cómo puede estar
seguro de que la variable var tiene el
valor 23 después de la llamada? Puede
que var no tuviese el valor inicial de 0,
porque otra llamada anterior ya podría
haberla asignado. Lo único que podría-
mos hacer es llamar a reset_variable() y
así asegurarnos de que nuestro valor sea
asignado, pero entonces destruiríamos el
valor anterior y no sabríamos qué podría
pasar.
Por lo tanto, necesitamos un meca-
nismo de comunicación para darle a
conocer al usuario que esa variable ya
está asignada. Esto lo podemos hacer
con las excepciones.
En el Listado 2 aparece una clase que
hereda de la clase Exception llamada
Var_Asignada. Cuando en la clase
obj_variable intentamos asignar un valor
a la variable var y ésta no es 0, entonces
se dispara, se eleva, la excepción
Var_Asignada. Si no controlamos la por-
ción de código en la que se encuentra
set_variable() y aparece una excepción,
el programa se detendrá y acabará.
La idea detrás de las excepciones es
que es posible tratarlas y evitar males
mayores, pudiendo en ocasiones incluso
recuperarnos de ellas. Para ello está la
estructura try—except, con la cual rodea-
mos el código que puede disparar excep-
ciones (Véase el Listado 3).
A partir de ahora, y hasta que no expli-
quemos con más profundidad el tema de
las excepciones, cuando digamos que
una función genera una excepción, signi-
ficará que ese código deberá estar rode-
ado con una estructura try—except.
Trabajo con Ficheros
Ya que hemos conseguido cierta soltura
con los conceptos de objetos en Python,
ahora vamos a ver cómo se manejan los
accesos a ficheros en él.
Para acceder a un fichero, primero
necesitamos crear un objeto file. El
objeto file es parte de la librería base de
Python, así que no es necesario importar
ninguna librería.
>>> archivo = file(‘texto.txt’)
Por definición, file abre los ficheros en
modo de sólo lectura. Eso significa que si
el fichero no existe, obtendremos un
error. Para verificar si el fichero existe
podemos usar la función exists() de la
librería os.path.
>>> import os.path >>>
os.path.exists(‘texto.txt’) True
>>> os.path.extsts(‘algo-
peludo-y-feo.txt’) False
Por lo tanto, si vamos a abrir un
fichero, podemos asegurarnos de que ya
existe.
Si en lugar de leerlo lo que queremos
es crearlo, deberemos invocar al cons-
tructor de file con los parámetros:
>>> archivo = file(‘texto.txt’,U
‘w’)
Este segundo parámetro opcional nos
permite definir el tipo de acceso que
vamos a realizar al fichero. Tenemos
varias posibilidades: podemos leer (r),
escribir (w), añadir al final del fichero
(a) y también tenemos el acceso de lec-
tura/escritura (r+w). Disponemos tam-
bién del modificador b para indicar
acceso binario. Por defecto, Python con-
Siguiendo con nuestro paseo por Python, vemos
características básicas, y concretamente en este
artículo, el tratamiento de ficheros. Por José Mari Ruíz
RuslanOlinchuk-123RF.com
Manejo básico de ficheros
Álbum
Fotográfico
sidera todos los ficheros de texto. Vemos
todas las combinaciones en el Listado 4.
Si todo ha ido bien, con cualquiera de
estas llamadas tendríamos en archivo un
objeto que gestiona el archivo indicado.
Ahora podemos operar sobre él.
Las operaciones más típicas son las de
leer desde el archivo y escribir en él. Para
ello, el objeto file dispone de los métodos
read(), readline(), write() y writeline().
Todos ellos operan con cadenas de carac-
teres: readline() y writeline() trabajan
con líneas de texto (acabadas en retorno
de carro), mientras que read() y write()
lo hacen con cadenas sin restricciones.
Lo que vemos en el Listado 5 son
algunas manipulaciones sobre un
fichero. Lo primero que tenemos que
hacer es crear el fichero, para lo cual lo
abrimos en modo de escritura, w, que lo
creará o truncará el existente (lo borrará
para crearlo de nuevo. Si lo hubiéramos
querido añadir al final, habríamos usado
a). Posteriormente escribimos en él una
cadena con un retorno de carro en mitad
(para hacer nuestras pruebas) y cerra-
mos el fichero. Es importante cerrar los
ficheros cuando dejemos de usarlos,
pero en este caso la razón para cerrarlo
es que vamos a volver a abrirlo en modo
de lectura.
Ahora volvemos a abrir el fichero en
modo de lectura, y leemos 4 bytes que
almacenamos en la variable cadena.
Cuando leemos con read(), avanzamos
en el fichero, siendo esta la razón de que
readline() que viene a continuación lea
la cadena “ mundon” en lugar de “Hola
mundo”. También vemos que se para en
el retorno de carro en lugar de continuar.
El segundo readline() ya nos permite
leer la cadena “Adiós mundo”.
Pero… ¿qué ocurriría si en una de las
lecturas nos encontrásemos con el fin de
fichero? En el caso de que leyésemos una
cadena con el fin de fichero (EOF), al
final simplemente nos quedaríamos con
la cadena hasta el EOF. En cambio, si
sólo leemos el EOF, entonces obtenemos
una null. Esto es importante para com-
probar que hemos acabado con el
fichero. Así, un bucle que escriba por
pantalla el contenido del fichero compro-
baría en cada vuelta si la cadena que
devuelve readline() es null.
Ahora que ya sabemos crear archivos,
tenemos que aprender a borrarlos. Esto
se realiza mediante la función remove()
de la librería os. Esta función acepta la
ruta de un fichero y lo borra. Si en lugar
de un fichero le pasamos un directorio
elevará una excepción OSError.
>>> import os
>>> os.remove (texto.txt)
>>>
Directorios y Sistema de Ficheros
Con estos pocos métodos tenemos ya a
nuestro alcance la manipulación básica
de ficheros. Pero vamos a necesitar para
nuestro programa la posibilidad de crear
directorios. ¿Cómo lo haremos? Pues
mediante la función mkdir(), que acepta
una cadena y crea un directorio con ese
nombre. Si queremos crear un directorio
que esté dentro de otros directorios tam-
bién nuevos tenemos que usar make-
dirs(). Ambas funciones pertenecen al
módulo os, por lo que para usarlas ten-
dremos que hacer:
>>> import os
>>> os.mkdir(‘uno’)
>>> os.makedirs(‘dos/tres’)
Para borrar esos directorios usaremos las
funciones rmdir() y removedirs(). La pri-
mera borra un directorio, mientras que
la segunda borra una ruta de directorios.
Vamos a ver esto con más detenimiento.
>>> os.rmdir(‘uno’)
>>> os.removedirs(‘dos/tres’)
rmdir() borrará el directorio “uno”, que
no contiene ningún otro objeto en su
interior (ni directorios, ni ficheros). En
caso de tenerlo, la llamada devolvería un
error. La función removedirs() comenza-
ría a borrar desde el directorio que está
más a la derecha de la ruta (“tres”) hacia
el que está más a la izquierda (“dos”).
Pero imaginemos que dentro de “dos”
también hay un directorio “cuatro”.
Entonces se borraría el directorio “tres”,
y cuando la función fuese a borrar el
directorio “dos”, se encontraría con que
no puede porque existe dentro de él un
directorio llamado “cuatro” y pararía.
Imaginemos ahora que necesitamos
cambiar el directorio en el que estamos
trabajando. En el momento de arrancar
el programa, el llamado “directorio de
trabajo” – es decir, el directorio donde de
manera predeterminada se realizarán
todos los cambios – es el directorio que
alberga el programa o bien el directorio
desde el que se ejecutó. Pero, claro, no
siempre querremos que el programa uti-
lice ese directorio.
Hay que tener en cuenta que, a no ser
que utilicemos rutas absolutas, cualquier
referencia a un fichero se tomará con
relación al directorio de trabajo inicial.
Para poder cambiar el directorio de tra-
bajo, el módulo os tiene la función
chdir(). Si lo invocamos dentro de nues-
tro programa:
>>> os.chdir(‘/tmp’)
Desde ese momento, cualquier referencia
a un fichero será direccionada a “/tmp”.
Ahora podemos:
• abrir, cerrar, modificar ficheros
• crear, eliminar un directorio
• cambiar el directorio de trabajo
Vamos a ir un poco más allá.
Llamadas a Otros Programas
A veces es más sencillo usar una utilidad
del sistema operativo que crearla noso-
INTRODUCCIÓNFicheros
11PYTHONWWW.LINUX- MAGAZINE.ES W W W. L I N U X - M A G A Z I N E . E S
01 class obj_variable:
02 __init__(this):
03 var = 0
04
05 set_variable(this, valor):
06 if (var == 0):
07 var = valor
08
09 reset_variable(this):
10 var = 0
Listado 1: Una Clase Python
01 class Var_Asignada(Exception):
02 “”“ Excepción que se dispara al
intentar asignar una variable ya
asignada en obj_variable”“”
03 pass
04
05 class obj_variable:
06 “”“ Administra una variable “”“
07 def __init__(self):
08 self.var = 0
09
10 def set_variable(self, valor):
11 if (self.var == 0):
12 self.var = valor
13 else:
14 raise Var_Asignada
15 def reset_variable(self):
16 self.var = 0
17
18 a = obj_variable()
19 a.set_variable(12)
20 a.set_variable(34)
Listado 2: Uso de Excepciones
INTRODUCCIÓN Ficheros
12 PYTHON WWW.LINUX- MAGAZINE.ES
En este apartado vamos a comenzar
con lo básico. Queremos traer un recurso
de la red a nuestra máquina, y para ello
emplearemos una URL del estilo http://
www.algunaweb.algo/imagen.jpg. Pero
primero necesitamos crear una conexión
con el servidor.
Para ello vamos a utilizar la librería
httplib que viene de serie con Python.
Esta librería nos permite establecer una
conexión con un servidor http y man-
darle comandos. Los comandos http
son simples, y de todos ellos sólo nos
interesa uno, el comando GET. Cuando
accedemos a un servidor http, por
ejemplo para ver una página web, lo
que hacemos es pedirle objetos. Esto se
hace mediante el comando GET
<objeto>. Por ejemplo, si queremos la
página index.html de la web http://
www.python.org, primero conectamos
con el servidor http y después, una vez
conectados, le enviamos el comando
GET index.html. En ese momento el
servidor nos devuelve por el mismo
canal el contenido del archivo
index.html.
Dicho así parece muy fácil, pero es
una tarea que en un lenguaje de más
bajo nivel requeriría gran cantidad de
librerías y control de errores.
Lo primero es importar la librería
httplib. Creamos entonces una conexión
con el host en cuestión y pedimos el
archivo index.html. Esa conexión genera
una respuesta. La respuesta está for-
mada por varias partes, entre ellas un
código numérico (como el famoso 404),
un texto que describe el error y una
conexión al archivo que pedimos. En el
caso de una conexión correcta recibire-
mos un 200, un OK y una conexión con
el fichero. De esa conexión lee-
mos con read() el contenido y
lo almacenamos en una varia-
ble que llamamos dato. Enton-
ces podremos cerrar la cone-
xión como si de un fichero se
tratara.
En ese momento ya tenemos
la información que queríamos
en dato y el canal cerrado. No
es muy difícil, ¿no? Veremos un
ejemplo en el programa final de
este artículo.
Paso de Parámetros
Estamos acostumbrados a
poder pasar parámetros a los
programas. En UNIX es algo común.
Pero… ¿cómo podemos obtener los pará-
metros de ejecución en Python? De
nuevo tenemos que recurrir a una libre-
ría: la librería sys.
sys nos proporciona el acceso a los
argumentos a través de su variable argv.
Esta variable es en realidad una lista, por
lo que podemos obtener los argumentos
accediendo a las posiciones de la misma.
La posición 0 contiene el nombre del
programa que estamos ejecutando y, a
partir de la posición 1, encontraremos
los parámetros pasados. Al ser una lista,
podemos conocer la cantidad de paráme-
tros llamando a len().
Programa
Ahora es el momento de poner todo lo
aprendido en práctica con un programa
que puede ser útil. En este caso vamos a
crear uno que realizará las siguientes
tareas:
• El programa aceptará un parámetro de
entrada que le indicará el nombre de
un fichero.
• El programa abrirá ese fichero y lo
leerá línea por línea. Cada línea del
fichero será la dirección URL de una
imagen.
• Cada URL será introducida dentro de
una lista para su uso posterior.
tros, como por ejemplo, un procesado
usando tuberías en UNIX. Puede que
simplemente tenga que acceder a alguna
información como la que nos da uname.
El caso es que siempre es importante
tener la posibilidad de ejecutar otros pro-
gramas desde nuestro programa Python.
Para ello usamos la función system del
módulo os. Por ejemplo:
>>> import os
>>> os.system (‘uname -a’)
Linux rachel 3.1.2-1.fc16.x86_64
#1 SMP Tue Nov 22 09:00:57 UTC 2011
x86_64 x86_64 x86_64 GNU/Linux
0
>>>
El parámetro que le pasamos a system es
una cadena con la instrucción Bash (en
este caso) y sus switches y flags. system
nos devuelve la salida de la instrucción (
Linux rachel 3.1.2-1.fc16.x86_64 #1 SMP
Tue Nov 22 09:00:57 UTC 2011 x86_64
x86_64 x86_64 GNU/Linux) y el estado de
salida resultante de la ejecución de la ins-
trucción (0 – recuérdese que 0 indica que
la instrucción ha acabado sin errores).
Python y la Web
Python posee gran cantidad de librerías
para trabajar con recursos de Internet.
De hecho, Django [1] , un servidor de
aplicaciones con gran éxito, está creado
en Python y hace uso de todas sus carac-
terísticas. Mailman [2] o Bittorrent [3]
son también buenos ejemplos.
Debido a su flexibilidad, Python es
usado como lenguaje de implementación
para multitud de aplicaciones de red así
como aplicaciones distribuidas. Por eso,
no es de extrañar que Python suela ser el
lenguaje en el que se implementan
muchas de las más novedosas tecnolo-
gías de red.
01 >>> try:
02 ... set_variable(12)
03 ... set_variable(34)
04 ... except:
05 ... print “ERROR: Se ha intentado
asignar”
06 ... print “un valor a una
variable ya asignada”
07 ...
08 ERROR: Se ha intentado asignar
09 un valor a una variable ya
asignada
10 >>>
Listado 3: Más Excepciones
01 >>> archivo = file(‘/tmp/texto.txt’,’w’)
02 >>> archivo.write(“Hola mundonAdios
mundo”)
03 >>> archivo.close()
04 >>>
05 >>> archivo = file(‘/tmp/texto.txt’,’r’)
06 >>> cadena = archivo.read(4)
07 >>> cadena
08 ‘Hola’
09 >>> cadena = archivo.readline()
10 >>> cadena
11 ‘ mundon’
12 >>> cadena = archivo.readline()
13 >>> print cadena
14 ‘Adios mundo’
15 >>> archivo.close()
Listado 5: Lectura y Escritura de Ficheros
01 archivo = file(‘texto.txt’,’r’)
02 archivo = file(‘texto.txt’,’w’)
03 archivo = file(‘texto.txt’,’a’)
04 archivo =
file(‘texto.txt’,’r+w’)
05 archivo =
file(‘texto.txt’,’r+b’)
06 archivo = file(‘texto.txt’,’rb’)
Listado 4: Acceso a Ficheros
INTRODUCCIÓNFicheros
13PYTHONWWW.LINUX- MAGAZINE.ES
001 #!/usr/bin/python
002
003 # ---NOTA--------------------------------------
004 # El fichero que debe ser pasado como argumento
005 # debe consistir en un listado con una url por
006 # línea.
007 # ---------------------------------------------
008
009 class Lista_URLs:
010 “”“Recibe un fichero y carga sus cadenas en una
lista. Provee de métodos para obtener de nuevo las
cadenas desde la lista.”“”
011
012 def __init__(self,nombre):
013 # La lista donde guardaremos las URLs
014 self.lista= []
015 # El contador que usaremos para comprobaciones
016 self.contador = 0
017
018 # pasamos el nombre del fichero menos el último
carácter
019 self.archivo = file(nombre)
020 self.cadena = self.archivo.readline()
021
022 while(self.cadena != ‘n’):
023 #Metemos la cadena en la lista
024 self.lista.append(self.cadena)
025 self.cadena = self.archivo.readline()
026 self.archivo.close()
027
028
029 def rebobina(self):
030 # Hace que se comience de nuevo
031 # por el principio en la lista.
032 self.contador = 0
033
034
035 def siguiente(self):
036 # Devuelve el siguiente elemento o
037 # ‘’ en caso de llegar al final.
038 if ( self.contador >= len(self.lista)):
039 return ‘’
040 else:
041 self.valor = self.lista[self.contador]
042 self.contador = self.contador + 1
043 return self.valor
044
045 def fin(self):
046 # Comprueba que hemos llegado al final
047 # de la lista. Preguntamos si hemos llegado
048 # al final antes de avanzar.
049 return (self.contador == len(self.lista))
050
051 def crea_directorio(cadena):
052 # Comprueba si el directorio especificado por
053 # cadena existe, en caso contrario lo crea
054 # y cambia el directorio de trabajo
055 # al directorio creado.
056
057 componentes = cadena.split(‘.’)
058
059 if(os.path.exists(componentes[0])):
060 print “Error: el directorio ya existe”
061 sys.exit()
062 else:
063 # Creamos el directorio
064 os.makedirs(componentes[0])
065 os.chdir(componentes[0])
066 print ‘Creando directorio ‘ + componentes[0]
067
068 def descarga_urls(lista):
069 # Recorre la lista de urls usando el objeto
070 # Lista_URLs, las descarga y después las
071 # guarda en ficheros con el mismo nombre que
072 # el de la imagen.
073
074 lista.rebobina()
075
076 while( not lista.fin() ):
077 url = lista.siguiente()
078
079 # dividimos la url en dos partes
080 # lo que descargamos y la url http
081
082 # Componentes es una lista que contiene
083 # las cadenas resultantes de trocear la
084 # cadena de texto de la URL usando ‘/’
085 # como separador. Por ejemplo:
086 # http://www.python.org/index.html
087 # componentes = [‘http:’, ‘’, ‘www.python.org’,
088 # ‘index.html’]
089 componentes = url.split(‘/’)
090 servidor = componentes[2]
091
092 # Construimos la ruta de la imagen, que
093 # consiste en toda la ruta si eliminamos
094 # al servidor y a http://
095 ruta_imagen = ‘/’
096 for i in range( 3, len(componentes)):
097 ruta_imagen = ruta_imagen + ‘/’ + componentes[i]
098
099 # Descarga el fichero y lo guarda con el nombre.
100 # El nombre se saca de la URL.
101 # url[:-1] es la cadena url menos el último carácter.
102 print ‘Descargando imagen: ‘ + url[:-1]
103 conexion = httplib.HTTPConnection(servidor)
104 conexion.request(“GET”, ruta_imagen)
105 respuesta = conexion.getresponse()
106 # datos contiene ahora la imagen y la guardamos
107 datos = respuesta.read()
108 conexion.close()
109
110 # el nombre del fichero es el último elemento
111 # de la lista componentes
112 nomb_fichero = componentes[len(componentes) -1]
113 # eliminamos el n final
114 nomb_fichero = nomb_fichero[:-1]
115
116 # Abrimos el fichero, escribimos y cerramos
117 archivo = file(nomb_fichero ,’w’)
118 archivo.write(datos)
119 archivo.close()
120
121 def genera_index(lista):
122
123 # Crea un fichero index.html.
124 # Genera la cabecera, recorre la lista de URLS
125 # y por último escribe el pie.
126 # Es posible mejorarlo introduciendo separadores
127 # o títulos entre las imágenes ;)
128
Listado 6: Agarrafotos.py
• Leer las URLs.
• Crear Directorio y cambiar el directo-
rio de trabajo.
• Descargar las URLs.
• Generar el archivo HTML.
Seguiremos estos puntos para crear las
funciones. Las URLs las almacenaremos
en una lista. ¿Deberíamos usar objetos?
Esta es una de las cosas maravillosas que
ofrece Python: NO estamos obligados a
usar objetos. Y no digo que los objetos
sean malos, sino que en ocasiones pue-
den llegar a ser engorrosos. Por ejemplo,
podríamos crear un objeto Lista_URLs
que aceptase como parámetro en su
constructor el nombre de un fichero y
que después nos permitiese ir cogiendo
las URLs una detrás de otra. También
podemos hacer lo mismo usando una
función que cargue las URLs en una
variable global. Aquí vamos a hacerlo
con un objeto. Es en este momento
cuando se deja al lector que explore la
posibilidad de sustituir el objeto por una
variable global y las funciones de lista.
Este programa es muy simple, pero de
nuevo retamos a los lectores a mejorarlo
y a introducirle, por ejemplo, control de
excepciones.
Suerte. ■
• Una vez que hayamos acabado de leer
el fichero, lo cerraremos y entraremos
en la segunda parte del programa.
• Crearemos un directorio con el nom-
bre del archivo que nos hayan dado.
• Cambiaremos el directorio de trabajo a
ese directorio.
• Descargaremos cada una de las URLs
dentro del directorio.
• Generaremos un archivo index.html
que muestre las imágenes.
¿Mucho trabajo? Para eso están los pro-
gramas. Evidentemente no realizaremos
todas las comprobaciones que serían
necesarias, ya que en tal caso el pro-
grama se alargaría demasiado, por lo que
se deja al lector la opción de incluir
mejoras. Pensemos ahora en su diseño.
Tenemos varias partes:
• Comprobar y almacenar la opción con
el nombre del archivo.
INTRODUCCIÓN Ficheros
14 PYTHON WWW.LINUX- MAGAZINE.ES
[1] La infraestructura Django para aplica-
ciones web:
https://www.djangoproject.com/
[2] El programa administrador de listas
de correo Mailman: http://www.gnu.
org/software/mailman/
[3] El programar para administración de
Torrente BitTorrent:
http://bittorrent.com/
Recursos
129 print ‘Generando índice index.html’
130
131 archivo = file(‘index.html’,’w’)
132
133 # Cabecera
134 archivo.write(‘<html>n’)
135 archivo.write(‘<head>n’)
136 archivo.write(‘<title> Imagenes </title>n’)
137 archivo.write(‘</head>n’)
138 archivo.write(‘<body>n’)
139 archivo.write(‘<h1>Imagenes</h1>n’)
140 archivo.write(‘<ul>n’)
141
142 # siempre antes de recorrer:
143 lista.rebobina()
144 url = lista.siguiente()
145
146 # Dividimos la URL para poder utilizar
147 # partes de ella.
148 componentes = url.split(‘/’)
149 imagen = componentes[len(componentes) - 1]
150
151 # Recorremos las urls
152 while( url != ‘’):
153 # Imagen en HTML
154 archivo.write(‘<li><img src=”‘+ imagen
+’”></img></li>n’)
155 url = lista.siguiente()
156 componentes = url.split(‘/’)
157 imagen = componentes[len(componentes) - 1]
158
159 # ... y por último el pie.
160
161 archivo.write(‘</ul>n’)
162 archivo.write(‘</body>n’)
163 archivo.write(‘</html>n’)
164
165 archivo.close()
166
167 #------------------------------------------------
168 # Main
169 #------------------------------------------------
170
171 # Esta es la técnica estándar para organizar el
172 # código en Python, se usa la siguiente construcción
173 # como punto de arranque.
174
175 if __name__ == ‘__main__’:
176
177 import httplib
178 import os
179 import os.path
180 import sys
181
182 # Comprobamos los argumentos...
183
184 if len(sys.argv) == 2:
185 #Pasamos el fichero al constructor
186 lista = Lista_URLs(sys.argv[1])
187
188
189 crea_directorio(sys.argv[1])
190
191 descarga_urls(lista)
192
193 genera_index(lista)
194
195 elif len(sys.argv) == 0:
196 # Vaya, han ejecutado sin poner argumentos...
197 # les recordaremos como va esto ;)
198 print ‘La sintaxis del programa es:n’
199 print sys.argv[0] + ‘ archivon’
200 print ‘El archivo debe contener una URL por línea’
201
202 else:
203 # Alguien se ha quedado corto y se ha pasado
204 # con el número de argumentos.
205 print “ERROR: la sintaxis es “ + sys.argv[0] + “
<fichero>”
Listado 6: Agarrafotos.py (Cont.)
Equivocarse es humano, y a pesar de
todo el mito que rodea a los programado-
res, hasta el mejor de ellos comete erro-
res diariamente. En muchas ocasiones es
mucho más complicado eliminar un BUG
que crear el propio programa. Cuenta le
leyenda que el nombre de BUG viene de
la misma palabra que en inglés significa
bicho. Dicen que los primeros ordenado-
res eran grandes máquinas que genera-
ban gran cantidad de calor, por lo que
innumerables insectos y otras alimañas
se introducían en ellos. De vez en
cuando, alguno tocaba dos cables y que-
daba frito, provocando un fallo en el sis-
tema. Actualmente se conoce como BUG
a todo error o situación no controlada
que impida a un programa realizar tu
tarea con normalidad. Lo cierto es que
estamos bastante acostumbrados a que
los BUGS sean parte de nuestra vida.
Ventanas que no se cierran, programas
que consumen todo el espacio en memo-
ria o videojuegos que se quedan blo-
queados.
Python es un lenguaje dinámico, como
muchos otros. La principal ventaja es
que nos permite programar a alto nivel,
desentendiéndonos de toda la gestión de
recursos a bajo nivel que hace tan
pesada la programación en otros lengua-
jes como por ejemplo C. Pero no todo el
monte es orégano. También hay una
parte negativa: Python no es un lenguaje
demasiado estricto. Podemos hacer lo
que queramos con las variables sin que
el intérprete se queje hasta el último
momento. Esta característica impide la
posibilidad de verificar automáticamente
todo el código en el momento en que es
compilado. Un código totalmente erró-
neo, en el que por ejemplo se suman
letras y números, puede pasar desaperci-
bido en nuestro programa hasta el día
que se ejecuta y genera un error que
dejará al usuario con la boca abierta, y
ciertas dudas sobre nuestra valía como
programadores.
Casi a la vez que surgieron los lengua-
jes de programación aparecieron unos
programas que han ido unidos a ellos:
los debuggers. Exiten muchos debuggers
diferentes. GNU desarrolló DDD, pero
hace tiempo que no se ve actividad en
este proyecto (ver Recurso [1]). Valgrind
ha conseguido mucha fama en proyectos
que emplean C++ ( ver Recurso [2]).
En este artículo vamos a echar un vis-
tazo a las herramientas que podemos
usar para localizar los fallos en nuestros
programas Python, y en particular a la
que viene de serie con Python: el PDB,
Python DeBugger (podemos ver la docu-
mentación de PDB en el Recurso [3]).
Un Bug, Dos Bugs, Tres Bugs…
Los lenguajes dinámicos, como decía-
mos antes, tienen sus propias virtudes y
desventajas. Los programadores más
duros suelen decir que programar con
lenguajes dinámicos es como jugar con
juguetes: no hay bordes cortantes con
los que cortarse ni partes pequeñas con
las que atragantarnos. Vamos, que son
poco menos que una versión infantil de
los lenguajes “serios”. Lo cierto es que
hay mucha gente que no entra en estos
debates. Yo, por lo menos, prefiero hacer
un programa tan rápido como sea posi-
ble y espero que funcione casi a la pri-
mera.
¿De dónde salen los BUGS? Lo más
probable es que haya siempre una varia-
ble implicada. La explicación es simple:
las variables son la única parte del pro-
grama que realmente no controlamos.
Mientras el resto del código hace exacta-
mente lo que le indicamos que haga, por
ejemplo abrir un fichero, en las variables
suceden todo tipo de cosas mientras el
INTRODUCCIÓNDebugging
15PYTHONWWW.LINUX- MAGAZINE.ES
Da igual lo buenos programadores que seamos, tarde o temprano daremos con ese BUG que
será nuestro peor enemigo. Veamos cómo podemos emplear herramientas para derrotarlo
con mayor facilidad. Por José María Ruíz
Eliminación de bugs de programas Python
Desparasitando
Serpientes
SebastianKaulitzki-123RF.com
INTRODUCCIÓN Debugging
16 PYTHON WWW.LINUX- MAGAZINE.ES
programa está en ejecución. El problema
es que no vemos esas variables mientras
el programa está funcionando, así que
tenemos que imaginarnos qué está
pasando.
En condiciones ideales se puede per-
der el tiempo tratando de localizar los
fallos a ojo de buen cubero, pero bajo
estrés y con plazos, toda ayuda es poca.
Python además nos permite almacenar
cualquier valor dentro de una variable.
Las variables en los lenguajes dinámicos
como Python son casi mágicas. En ellas
podemos almacenar un número:
>>> mivariable = 32
Y punto seguido almacenar un objeto:
>>> class Persona:
... def __init__(this,nombre):
... this.nombre = nombre
...
>>> mivariable = PersonaU
(‘Carlos’)
Y sigue siendo la misma mivariable, pero
de alguna manera su naturaleza ha cam-
biado. Ahora imagina que esta situación
ocurre en un programa que has creado.
Mientras tecleas piensas, “‘mivariable’
contiene una distancia” y operas con ella,
sólo que, sin que te des cuenta, en reali-
dad mivariable contiene un objeto de la
clase Persona ¿qué pasara si intentas
sumarle 18?
>>> a + 18
Traceback (most recent call last):
File “<stdin>”, line 1, in ?
TypeError: unsupported operand
type(s) for +: ‘instance’ and ’int’
>>>
¡ERROR! El intérprete de Python nos
advierte de que algo no marcha bien:
hay un error de tipo, no es posible
sumar un número entero y una instancia
de un objeto tal como hemos definido la
clase. Desagradable ¿verdad? Por lo
menos este tipo de BUG, que es tan fácil
de encontrar que el propio intérprete de
Python lo encuentra. ¿Qué ocurría si el
programa no fallase, sino que no nos
diese el resultado esperado? ¿Y si el pro-
grama le dijese a un cliente que su edad
actual es -323134.32 años? Este es sin
duda el peor tipo de BUG existente: el
semántico.
El intérprete de Python es perfecto
localizando errores sintácticos, aquéllos
que tienen que ver con las propias pala-
bas que escribimos. Si hacemos referen-
cia a una variable que no está definida,
Python trata de buscar su valor, ve que
no existe la variable y se queja.
Los errores semánticos son harina de
otro costal, porque se refieren a fallos que
aparecen debido a que no se entiende lo
que está pasando. Un ejemplo simple es
el que hemos visto antes, cuando hemos
tratado de sumar una variable con una
instancia de un objeto que no responde a
la suma con un número.
Solucionar un BUG semántico puede
llevar desde segundos a años. De hecho,
existe mucho software, tanto comercial
como libre, con BUGS que no han sido
resueltos en años. Ahora que el pro-
blema ha sido planteado con más deteni-
miento, conviene ver con qué arsenal
contamos en nuestra batalla contra los
BUGS.
Depurando Código
Digamos que estamos haciendo un script
para mostrar, usando como caracteres las
vacaciones que han escogido una serie de
empleados de una empresa. Como no
queremos que el código sea largo ni
demasiado complicado, lo hemos redu-
cido al mínimo. La función tomará una
lista de tuplas, que representa las vaca-
ciones de una persona en un mes. Cada
tupla representa un periodo de vacacio-
nes, con una fecha de inicio y una fecha
de fin. La idea es muy simple, aceptamos
esa lista y después devolvemos una
cadena donde los días de trabajo se
representan por un espacio, y los de
vacaciones con un “#”. No es muy com-
plicado ¿verdad?
Así que nos ponemos manos a la obra,
es algo sencillo, no nos llevará ni 10
minutos, acabamos escribiendo el
código del Listado 1. Pero nos interrum-
pen antes de probar la función, y
cuando volvemos al ordenador y ejecu-
tamos un programa de prueba ¡se queda
bloqueado! ¡No puede ser!, en tan pocas
líneas de código no puede haber un
error tan grave. Después de unos minu-
tos de frustración, abandonamos la ins-
pección visual y pasamos a trabajar
PDB.
PDB es el Python DeBugger y viene de
serie con Python. Eso está muy bien,
porque en caso de necesitarlo siempre lo
tendremos a mano. A diferencia de otros
debuggers, PDB se puede usar como si
fuese una librería. Podemos integrarla en
nuestros programas y eliminarla cuando
ya los hayamos arreglado. Como es posi-
ble observar en el Listado 1, hemos
importado PDB y hemos pasado como
parámetro a pdb.run() una cadena en la
que invocamos la función vacaciones()
con un argumento acorde. Si ejecutamos
el programa, veremos lo siguiente en
nuestro terminal:
josemaria@linuxmagazine$U
./p.py
> <string>(1)?()
(Pdb)
Figura 1: ¿A quién dejaremos sin vacaciones?
01 #!/usr/local/bin/python
02
03 import pdb
04
05 def vacaciones (l):
06 cadena = “”
07 for i in range(1,31):
08 encontrado = False
09 max = len(l)
10 k=0
11 while(not(encontrado) or
k<max):
12 rango = l[k]
13 inf,sup=rango
14 if ((i >= inf) and (i <= sup)):
15 encontrado = True
16 else:
17 k+=1
18
19 if (encontrado):
20 cadena += “#”
21 else:
22 cadena += “ “
23
24 return cadena
25
26 pdb.run(‘vaca-
ciones([(1,3),(6,10)])’)
Listado 1: El Código Nefasto
Muy bien, el PDB comienza a hacer su
trabajo. En lugar de no hacer nada, como
haría la función vacaciones() si el pro-
grama se limitase a ejecutarla, entramos
en lo que parece el prompt del shell de
PDB. Esta shell tiene sus propios coman-
dos, no tiene nada que ver con Python.
Para ver los comandos disponibles pode-
mos emplear el comando h:
(Pdb) h
Documented commands (type help
<topic>):
================================
EOF break condition disable help
list q step w
a bt cont down ignore n quit
tbreak whatis
alias c continue enable j
next r u where
args cl d exit jump p return
unalias
09 b clear debug h l pp s up
Miscellaneous help topics:
==========================
exec pdb
Undocumented commands:
======================
retval rv
(Pdb)
¡Buff! estos son demasiados comandos.
Como suele ocurrir la primera vez que
un principiante en Linux pulsa dos
veces tabulador en BASH, lo que vemos
nos asusta. En este caso no son tantos
comandos (en un Linux estándar hay
miles de ejecutables), pero sí más extra-
ños. Debuggear es algo que SIEMPRE se
hace bajo presión, por lo que todo el
tiempo que ahorremos es oro. Así que
los creadores de PDB nos ahorran
segundos reduciendo los comandos a
letras.
Podemos ver lo que hace un comando
usando de nuevo la letra h:
(Pdb) h l
l(ist) [first [,last]]
List source code for the current
file.
Without arguments, list 11 lines
around the current line
or continue the previous listing.
With one argument, list 11 lines
starting at that line.
With two arguments, list the given
range;
if the second argument is less than
the first, it is a count.
(Pdb)
El comando l sirve para mostrar visual-
mente en qué parte del código estamos
en un momento dado; como nos pica la
curiosidad ejecutamos l:
(Pdb) l
[EOF]
Vaya, resulta que no hemos comenzado
aún, por lo que no estamos en ninguna
parte. El comando que probablemente
usemos más a menudo es s ¿Por qué?
pues porque es el comando que hace que
PDB avance una línea y la ejecute:
(Pdb) s
--Call--
> /home/josemaria/p.py(5)U
vacaciones()
-> def vacaciones (l):
Muy bien, comenzamos a ejecutar el
trozo de código Python que pasamos a
pdb.run(). Por el momento no pasa nada
interesante, aunque estaría bien ver qué
contiene la variable l, para ello podemos
usar el comando p que hace las funciones
de print:
(Pdb) p l
[(1, 3), (6, 10)]
Efectivamente, l contiene el parámetro
que hemos pasado a la función. Ya esta-
mos en ruta, así que avancemos unos
cuantos pasos más:
(Pdb) s
> /home/josemaria/p.py(6)
vacaciones()
-> cadena = “”
(Pdb) s
> /home/josemaria/p.py(7)
vacaciones()
-> for i in range(1,31):
(Pdb) s
> /home/josemaria/p.py(8)
vacaciones()
-> encontrado = False
(Pdb) s
> /home/josemaria/p.py(9)
vacaciones()
-> max = len(l)
(Pdb)
Hemos avanzado 4 pasos y puede que
nos hallamos perdido. ¿Dónde estamos?
¿Qué estamos haciendo? ¿Hacia dónde
vamos? El comando l resuelve todas
nuestras dudas:
(Pdb) l
4
5 def vacaciones (l):
6 cadena = “”
7 for i in range(1,31):
8 encontrado = False
9 -> max = len(l)
10 k=0
11 while(not(encontrado)
or k<max):
12 rango = l[k]
13 inf,sup=rango
14 if ((i >= inf) and
(i <= sup)):
(Pdb)
Ya me sitúo, acabamos de entrar en el
bucle for, avancemos un poco más:
(Pdb) s
> /home/josemaria/p.py(10)U
vacaciones()
-> k=0
(Pdb) s
> /home/josemaria/p.py(11)U
vacaciones()
-> while(not(encontrado) orU
k<max):
(Pdb)
INTRODUCCIÓNDebugging
17PYTHONWWW.LINUX- MAGAZINE.ES
Figura 2: IDLE no es bello, pero es práctico.
Figura 3: El depurador de IDLE.
variable encontrado sea True. Si todo va
bien, el siguiente paso después de eva-
luar las condiciones del while será salir
del mismo y pasar a las siguiente instruc-
ción fuera del while:
(Pdb) s
> /home/josemaria/p.py(12)U
vacaciones()
-> rango = l[k]
(Pdb)
¿Pero qué ocurre aquí? Esto no debería
pasar. La única explicación posible es
que la condición del while esté… ¿es eso
un or? ¡Debería ser un and! Deberíamos
salir si hemos encontrado que el día per-
tenece a un rango, o si no quedan rangos
que comprobar. Ahí estaba nuestro BUG,
tres simples letras, se cambian y pro-
blema solucionado.
Ahora que ya sabemos lo que pasa,
sólo queda salir del debugger usando el
comando q. Nuestro nuevo código ya
está listo para ser usado (ver Figura 1).
Y Ahora de Forma Fácil
¿No hay una manera más «moderna» de
conseguir esto mismo? Pues sí, gracias a
IDLE (ver Recurso [4]).
IDLE es el entorno de desarrollo que
viene, también, junto a Python. En la
Figura 2 se puede observar el aspecto
que tiene IDLE una vez que se ejecuta.
No es ninguna belleza, pero es práctico,
reemplaza al intérprete de comandos de
Python y simplifica algunas tareas.
En particular, estamos interesados en
cómo puede simplificar el debugging.
Para ello sólo tenemos que ir al menú
Debug que aparece en la barra de menú
de IDLE y activar Debugger. Aparecerá
una ventana como la que puede obser-
varse en la Figura 3. El lector no debe
extrañarse demasiado con esta nueva
ventana, viene a condensar en un solo
lugar todo lo que hemos visto sobre
PDB: hay un botón llamado STEP, que
nos permitirá avanzar en el código paso
a paso, y también hay un área llamada
Locals, donde iremos viendo el valor de
las variables que se vayan declarando en
el código, de forma que podremos ir con-
trolando la evolución del programa de un
solo vistazo.
Para ello sólo tenemos que cargar el
programa en IDLE y veremos cómo se
abre una especie de editor de textos
como el de la Figura 4, en el que debere-
mos seleccionar en el menú Run la
opción Run Module. Con este paso carga-
remos el fichero y comenzaremos a eje-
cutarlo. Como antes seleccionamos la
opción Debugger, IDLE se cargará en la
ventana de debugging y podremos
comenzar a visionar la evolución del
programa conforme pulsemos sobre el
botón Step. No es que IDLE sea un gran
avance respecto al uso de PDB, pero
desde luego simplifica el debugging.
Conclusión
Los debuggers no son una excusa para
crear programas sin fijarnos demasiado
en los problemas. Pero si no tenemos
claro qué está ocurriendo o si ya no
sabemos qué hacer, entonces un debug-
ger como PDB puede ayudarnos a tener
una imagen más clara de lo que pasa en
nuestro programa. Existen bugs que no
pueden cazarse con PDB, pero son tan
extraordinariamente raros, que es posi-
ble que jamás nos encontremos con
uno.
Los debuggers nos permiten progra-
mar sin miedo a no entender lo que esta-
mos haciendo, y es precisamente eso lo
que nos permitirá avanzar y aprender
más rápidamente. ¡Perdámosle el miedo
a los BUGS! ■
Bueno, llegamos a una encrucijada.
Cuando ejecutamos la función sin PDB,
parece como si el programa nunca aca-
base. Esto implica que hay algo que se
repite eternamente. En este programa hay
dos bucles, que son los únicos elementos
que pueden repetirse eternamente. El pri-
mero es un bucle for con un principio, 1,
y un fin, 31, por lo que podemos descar-
tarlo como culpable. El segundo sospe-
choso es ese bucle while, que en un pri-
mer momento no tiene porqué acabar,
puede que jamás pare. Si un bucle while
no para es porque las condiciones que lo
controlan siempre se dan. En este código
se supone que el if dentro del bucle while
hace que éste pare alguna vez, así que
algo debe fallar ahí dentro. Comencemos
comprobando los valores de las variables
que controlan el bucle:
(Pdb) p encontrado
False
(Pdb) p k
0
(Pdb) p max
2
(Pdb)
De acuerdo, todo parece en su sitio. Si
avanzamos un poco:
> /home/josemaria/p.py(12)
vacaciones()
-> rango = l[k]
(Pdb) s
> /home/josemaria/p.py(13)
vacaciones()
-> inf,sup=rango
(Pdb) s
> /home/josemaria/p.py(14)
vacaciones()
-> if ((i >= inf) and
(i <= sup)):
(Pdb) s
> /home/josemaria/p.py(15)
vacaciones()
-> encontrado = True
(Pdb) s
> /home/josemaria/p.py(11)
vacaciones()
-> while(not(encontrado) or
k<max):
(Pdb)
Resulta que hemos entrado en una tupla
que representa unas vacaciones, el día
representado por i pertenece a las vaca-
ciones. Por tanto, hemos hecho que la
INTRODUCCIÓN Debugging
18 PYTHON WWW.LINUX- MAGAZINE.ES
[1] Documentación del depurador PDB:
http://docs.python.org/lib/module-
pdb.html
[2] Valgrind captura errores que compro-
meten la memoria en:
http://valgrind.org/
[3] Data Display Debugger:
http://www.gnu.org/software/ddd/
[4] El entorno de desarrollo IDLE:
http://www.python.org/idle/
Recursos
Figura 4: El seudo-editor de IDLE.
Existe un gran misticismo en torno a
los conceptos de función lambda y al
concepto de cierre. Siempre que aparece
un nuevo lenguaje de programación
suele venir acompañado de una discu-
sión que demuestra que el nuevo len-
guaje es mejor porque incorpora alguno
de estos dos conceptos. Quien esté un
poco al tanto de los últimos «avances»
habrá escuchado decir que C# incorpora
las funciones lambda y que la próxima
versión java al fin las tendrá entre su
arsenal.
Las funciones lambda reciben su nom-
bre de la teoría del cálculo lambda de
Alonzo Church [1], que junto a Alan
Turing, sentaron las bases de la teoría de
computación. Mientras Turing utilizó en
su teoría una máquina abstracta e imagi-
naria a la que se llamó Máquina de
Turing, Alonzo utilizó un enfoque más
tradicional, creando una serie de reglas
que permitían realizar computaciones.
Su sistema requería de un tipo de fun-
ción especial, para la que usó la letra
lambda. Las funciones lambda que vere-
mos comparten sólo algunas de las
características que Alonzo definió para
las suyas, y podemos decir que lo que las
define es que son anónimas: las funcio-
nes lambda no tienen nombre.
¿Cómo es esto posible? ¿Para qué que-
rríamos algo así? Son sólo dos preguntas
que trataremos de resolver en este artí-
culo mientras desmitificamos un con-
cepto tan abstracto a primera vista.
Las Funciones Lambda
Las funciones lambda son el concepto
más sencillo de los que vamos a ver en
este artículo. Python las soporta desde
hace un buen tiempo, y se encuentran
integradas en la librería base de Python.
También conocidas como funciones anó-
nimas, no son más que funciones sin
nombre que podemos crear en cualquier
momento y pasar como argumento a
otras funciones:
>>> a = lambda x : x + 1
>>> a(2)
3
>>>
Recordemos que en Python las variables
no son más que nombres que asignamos
a cosas y no contenedores de esas cosas.
Esta diferencia es vital para comprender
por qué podemos asignar una función a
una variable y posteriormente asignar un
valor a la misma (ver Figura 1).
En este sencillo ejemplo hemos creado
una función que suma el número 1 al
número que pasemos como argumento.
La definición de una función lambda
siempre comienza con la palabra lambda
seguida de los argumentos que vamos a
aceptar. Detrás de los argumentos usa-
mos el símbolo : para separar la defini-
ción del cuerpo de la función. Las fun-
ciones lambdas, al ser anónimas, deben
almacenarse en una variable si quere-
mos reutilizarlas, y se comportarán
AVANZADOFunciones Lambda
19PYTHONWWW.LINUX- MAGAZINE.ES
Funciones lambda en Python
Sin
Nombre
Python es un lenguaje de programación multiparadigma, y las
funciones lambda son parte fundamental de él, aunque como
veremos, existen buenas razones para no abusar de ellas.
Por José María Ruíz
©stylephotographs-123RF.com
AVANZADO Funciones Lambda
20 PYTHON WWW.LINUX- MAGAZINE.ES
como una función tradicional a la que
podremos llamar pasándole parámetros
entre dos paréntesis ().
Existen varias restricciones en el uso
de las funciones lambda. La primera es
que siempre deben devolver un valor.
Son funciones en el sentido estricto de
las matemáticas, aceptan valores, los
transforman y devuelven algún valor. En
Python podemos devolver varios valores
si lo deseamos:
>>> b = lambda x: (x,x+1)
>>> b(2)
(2,3)
>>>
La segunda restricción es que sólo pue-
den contener una expresión. Esta restric-
ción limita bastante el poder de las fun-
ciones lambda en Python. En Ruby, por
ejemplo, las funciones lambda (también
llamadas bloques) pueden contener tan-
tas expresiones como deseemos. En
Python se decidió añadir esta restricción
para que los desarrolladores terminaran
empleando las funciones lambda allí
donde una función tradicional podría
valerles (en Javascript es algo que se
hace habitualmente). Cuando violemos
una de estas restricciones, Python gene-
rará una excepción:
>>> c = lambda x: y = x+1
File “<stdin>”, line 1
c = lambda x: y = x+1
^
IndentationError: unexpected U
indent
En este caso hemos tratado de realizar
una asignación dentro de una función
lambda. Lo que sí podemos hacer es
pasar más de un parámetro a la fun-
ción:
>>> d = lambda x,y: x*y
>>> d(2,3)
6
>>>
Podemos, de forma limitada, emplear
sentencias condicionales, puesto que
Python nos permite usar la fórmula
if...else como si fuese una expresión:
>>> d = lambda x: ‘Yuju’ U
if x > 2 else ‘ooooh’
>>> d(2)
‘ooooh’
>>> d(3)
‘Yuju’
Pero… ¿Para qué Sirven?
Las limitaciones a las funciones lambda
en Python tienen un objetivo bien defi-
nido: evitar el mal uso que se puede
hacer de ellas. Se restringe su uso a
aquellas funciones donde es necesario
pasar operaciones sencillas que el dise-
ñador original de una función no puede
predecir de antemano. Por ejemplo, si
queremos ordenar una lista, la función
de ordenación sorted() intentará compa-
rar los elementos de la misma usando los
métodos que existen por defecto. Pero
¿qué ocurre si los datos a ordenar son
algo especiales? Imaginemos que tene-
mos una lista de datos donde cada ele-
mento es un tupla con el nombre y la
edad de una serie de personas:
>>> l = [(‘Luis’, 65), U
(‘Juan’,28),U
(‘Montse’, 33)]
¿Cómo podemos indicar a sorted que
queremos ordenar la lista por edades? El
diseñador de sorted no puede predecir
todas las posibles estructuras de datos
que se pasarán a la función. Existen tres
opciones, u obligamos a la
persona que pasa los datos
a encapsularlos en objetos
con un método que nos
permita comparar dos
objetos:
01 from functools import
total_ordering
02
03 @total_ordering
04 class Edad(object):
05 def __init__(self,
nombre,edad):
06 self.nombre = nombre
07 self.edad = edad
08
09 def __eq__(self, otro):
10 return cmp(self.edad,
otro.edad)
11
12 def __lt__(self, otro):
13 return self.edad <
otro.edad
14
15 def __str__(self):
16 return self.__repr__
17
18 def __repr__(self):
19 return u”({0} tiene {1})”
.format(self.nombre,
self.edad)
20
21 l = [Edad(‘Luis’, 65),
22 Edad(‘Juan’,28),
23 Edad(‘Montse’, 33),]
24
25 print sorted(l)
O bien definimos una función que nos
permita extraer el valor a comparar de
los objetos:
>>> def mi_ordenacion (x): U
return x[1]
>>> sorted(l, key = U
mi_ordenacion)
[(‘Juan’,28),(‘Montse’, 33), U
(‘Luis’, 65)]
>>>
O bien podemos emplear una función
lambda para generar los valores a com-
parar:
>>> sorted(l, key = U
lambda x: x[1])
[(‘Juan’,28),(‘Montse’, 33), U
(‘Luis’, 65)]
>>>
La primera opción, más clásica de len-
guajes como Java o C#, y (supuesta-
mente) más limpia, tiene un gran pro-
blema. ¿Qué ocurre si queremos ordenar
los datos de varias maneras diferentes?
El diseñador de sorted sólo empleará una
de ellas. Es un enfoque bastante inflexi-
ble, es preferible que la función que
selecciona el criterio de ordenación sea
externa al objeto a ordenar. Además,
como se puede observar, esta opción es
bastante más compleja.Figura 1: Las variables en Python son nombres.
La segunda opción implica el uso de
una función externa que nos devuelve el
valor a comparar para cada objeto. Indi-
camos a sorted qué función usar para
seleccionar los valores a comparar
mediante el parámetro key. Por último
vemos cómo se haría lo mismo con una
función lambda. Salta a la vista que la
tercera opción es la corta, fácil de leer y
elegante (o lo que es lo mismo, la más
«pythonic»).
El lenguaje de programación Common
Lisp se enfrentó a este mismo problema
cuando se diseñó su sistema de objetos,
y la solución fue la misma: sacar fuera
del objeto y de la función de ordenación
el código que genere los datos a compa-
rar. Python empleó la misma técnica, por
lo que mucha gente ve semejanzas entre
ambos lenguajes de programación.
Cierres
Otro de los conceptos que puede provo-
car más de un dolor de cabeza es el de
cierre. Lenguajes como Javascript giran
en torno a este concepto, ya que les per-
mite crear algo parecido a objetos, ver
Figura 2. En Python, sin embargo, los
cierres son la base de una de las caracte-
rísticas más usadas del lenguaje última-
mente: los decoradores.
Un cierre es un trozo de código fuente
que depende de variables, algunas de las
cuales han sido «capturadas» junto al
trozo de código y quedan aisladas de
cualquier interferencia externa. En el
caso de Javascript, que no posee objetos
propiamente dichos, se usan cierres para
que una serie de funciones compartan
unas variables que no pueden ser accedi-
das desde fuera y que por tanto están
protegidas.
En Python los cierres no funcionan
exactamente como lo hacen en otros len-
guajes. Siguiendo con las funciones
lambda, vamos a crear un cierre con una
de ellas:
>>> def crea_cierre(num):
... return lambda x=num: x+1
...
>>> cierre = crea_cierre(3)
>>> cierre()
4
>>> 4
Analicemos este código. La función
crea_cierre() acepta un parámetro num y
devuelve una función lambda, por lo que
el valor devuelto puede
almacenarse en una varia-
ble y se comportará como
una función. El secreto
está en pasar a la función
lambda el valor num que
queda definido como valor
por defecto para x. Lo
curioso es que en este caso
Python no nos permite
pasar ningún valor a la
función lambda una vez
definida. Si tratamos de
pasar un valor:
>>> cierre(10)
4
>>>
¡Nos sigue devolviendo 4!
No importa qué valor pase-
mos a la función, el contenido de x ha
quedado completamente cerrado y blo-
queado. Por así decirlo, su valor se ha
vuelto inaccesible. Si quisiéramos poder
cambiar el valor de una variable cerrada,
deberíamos usar una función normal en
lugar de una función lambda, porque
como ya vimos, las funciones lambda no
aceptan asignación de variables.
¿Tiene sentido usar cierres en Python?
El sistema de objetos de Python es muy
sencillo y nada engorroso, por lo que es
muy extraño ver el uso de cierres en
Python, salvo por una excepción: los
decoradores. Un decorador es una fun-
ción que intercepta los parámetros de
otra función, hace algo y devuelve la
función original. Normalmente no se cie-
rran variables en un decorador, pero es
posible hacerlo.
La respuesta de Python a los cierres de
funciones son los objetos callable. En
Python es posible crear un objeto que se
comporte como una función. La función
tendrá acceso a una serie de variables de
instancia que se pasan en el constructor
de la misma:
01 >>> class Saluda(object):
02 ... def __init__(self,
saludo):
03 ... self.saludo =
saludo
04 ... def __call__(self,
nombre):
05 ... print “{0} {1}”
.format(self.saludo, nombre)
06 ...
07 >>> saludo = Saluda(‘Hola’)
08 >>> saludo(‘mundo’)
09 Hola mundo
10 >>> saludo = Saluda(‘Hello’)
11 >>> saludo(‘world’)
12 Hello world
13 >>>
Creamos un objeto tradicional con la
única diferencia de poseer un método
llamado __call__, que será el que se eje-
cute cuando invoquemos la instancia de
la clase como si fuese una función. Pri-
mero debemos generar una instancia a la
que pasamos la variable de se «cerrará» y
posteriormente podemos invocar la ins-
tancia como si fuese una función que
acepta parámetros como cualquier otra
función.
Funciones de Primer Orden
Como ya hemos dicho, las funciones
lambda no son especialmente potentes
en Python – en Ruby lo son más – pero
nos permiten pasar comportamientos a
otras funciones. En teoría de lenguajes
de programación, se llama función de
primer orden a aquella función que
acepta otra función como parámetro,
acepta comportamientos además de
datos, lo que la hace especialmente
potente y flexible.
En Python es absolutamente normal
usar funciones como parámetros:
01 def saluda(x,
f=None):
02 if f:
AVANZADOFunciones Lambda
21PYTHONWWW.LINUX- MAGAZINE.ES
Figura 2: Cómo funciona un cierre en torno a una función.
metros. Primero aplicará la
función a «Luis» y «65»,
después a «Juan» y «28»… y
así indefinidamente. map
no está limitada a dos listas,
podemos emplear tantas lis-
tas como queramos:
>>> map(lambda x:
x.upper(),U
[‘Luis’, ‘Juan’U
, ‘Montse’])
[‘LUIS’, ‘JUAN’, U
‘MONTSE’]
>>> map(lambda x,y,z:U
(x, y*z),U
[‘Luis’, U
‘Juan’,’Montse’],U
[65,28,33], [1,2,3])
[(‘Luis’, 65),U
(‘Juan’, 56),U
(‘Montse’, 99)]
>>>
Aunque podríamos pasar
cualquier función previa-
mente definida, estamos pasando funcio-
nes lambda. Es la manera más sencilla y
rápida de aplicar map, aunque como ya
hemos dicho antes, si necesitamos más
de una operación o el código es complejo
es mejor definir la función.
Este map es el mismo que el del
famoso Map/Reduce de Google, con la
diferencia de que el de Google se aplica a
cientos o miles de máquinas, que aplican
funciones map muy complejas a gran
cantidad de datos. Pero el concepto es el
mismo.
Si este es el map… ¿dónde está
reduce?
>>> reduce(U
lambda x,y: x if x[1] > y[1] U
else y,U
[(‘Luis’, 65), (‘Juan’, 56),U
(‘Montse’, 19)])
(‘Luis’, 65)
>>>
reduce va a aplicar una función de 2
variables a los elementos de una lista
con el objetivo de acabar devolviendo un
solo elemento. Como su propio nombre
indica, reduce una lista a un elemento.
Aquí estamos buscando el valor más
grande de los presentes en la lista, por lo
que la función reductora compara los
dos parámetros y siempre devuelve el
mayor de ellos. Por lo tanto, map aplica
una función a una gran cantidad de
datos y reduce realiza alguna operación
sobre los datos que los convierte en un
solo valor.
A pesar de toda la fanfarria existente
alrededor de Map/Reduce, lo cierto es
que en Python se usan poco. De hecho,
reduce dejará de ser una función primi-
tiva del sistema en Python 3 y pasará a
ser una función de la librería functools,
por lo que ha sido degradada a ciuda-
dano de segunda fila.
Conclusión
Estamos tan acostumbrados ya a la pro-
gramación orientada a objetos, que se
nos olvida que Python en sus inicios
tomó prestados gran cantidad de concep-
tos y técnicas de otros modelos de pro-
gramación. Las funciones lambda no
están muy vistas como técnica de pro-
gramación, pero las restricciones a las
que las somete Python las ha domesti-
cado lo suficiente como para que en
lugar de entorpecer nuestro código lo
hagan más ligero y sencillo de compren-
der. ■
03 print f(x)
04 else:
05 print x
06 >>>
07 >>> saluda(“hola”)
08 hola
09 >>> saluda(“hola”,
f=lambda x: x.upper())
10 HOLA
11 >>>
Al fin y al cabo, las variables en Python
no son más que nombres que apuntan a
«cosas», sin importar demasiado qué
son esas cosas. No hay gran misterio en
las funciones de primer orden vistas así.
Es lo que haces con ellas lo que las
vuelve interesantes. Python nos provee
de un conjunto de funciones de primer
orden, heredadas de otros lenguajes de
programación funcionales, que nos per-
miten emplear funciones en sus opera-
ciones.
Map y Reduce
Cuando las funciones lambda realmente
brillan es cuando se usan en conjunción
con las funciones de filtrado y mapeo.
Con todo el revuelo generado por Goo-
gle y otras empresas en torno a las técni-
cas Map/Reduce, es interesante recordar
los humildes comienzos de estas técni-
cas.
El filtrado y mapeo son técnicas here-
dadas de la programación funcional, ver
Figura 3. En este estilo de programación
se evita modificar los datos originales, y
en lugar de ello se realizan una serie de
transformaciones sobre los datos para ir
reduciéndolos y operando sobre los
resultados hasta conseguir el resultado
deseado. El código resultante suele ser
conciso, aunque no siempre fácil de leer
y entender. La programación funcional
también hace uso de las funciones de
primer orden que hemos visto antes.
Comencemos por echar un vistazo a la
función map:
>>> map(lambda x,y: (x,y),U
[‘Luis’, ‘Juan’,’Montse’], U
[65,28,33])
[(‘Luis’, 65), (‘Juan’, 28), U
(‘Montse’, 33)]
>>>
map aplica una función a dos listas de
valores, recorriendo ambas listas de
valores y pasando los valores como pará-
AVANZADO Funciones Lambda
22 PYTHON WWW.LINUX- MAGAZINE.ES
[1] Alonzo Church: http://es.wikipedia.
org/wiki/Alonzo_Church
Recursos
Figura 3: Map y Reduce en acción.
No es ni será la última vez que desde
esta sección recordemos que la idea ori-
ginal de Stallman era la de que cada
programa libre estuviese construido
sobre librerías de funciones, de manera
que su código fuese reutilizable por
cualquier otro programa.
Quizás en un programa pequeño no
sea muy útil este tipo de diseño, pero
¿qué pasa con esos monstruos consum-
idores de memoria que rondan por
nuestros discos duros? Nos referimos a
programas o entornos del calibre de
Gnome, KDE, Mozilla u OpenOffice.
Todo el mundo se queja de su tamaño
excesivo, su alto consumo de recursos
y su inexplicable complejidad.
Quizás con este artículo desminta-
mos este mito y hagamos que el lector
mire con nuevos ojos a estos maravi-
llosos programas.
Grandes Sistemas de Componentes
El diseño de un gran programa puede
llevar años y cientos o miles de progra-
madores. Organizar tal cantidad de per-
sonas supone ya una locura sólo por el
hecho de asegurarse que todos cobren.
Pero vayamos a nuestro mundillo
¿cómo podemos organizarlos para que
el desarrollo no acabe en un fiasco?
Esta es la gran cuestión no resuelta
de la informática, pero, aunque no
hayamos encontrado una solución
fiable, sí se disponen de técnicas que
aumentan la probabilidad de que, al
menos, se cree algún software útil.
Una de estas técnicas consiste en
emplear un sistema de componentes
como base para el desarrollo. Un com-
ponente es una cantidad de software
que ofrece un servicio bien definido y
que es reutilizable. Además debe ser
posible reutilizarlo «de verdad»: desde
cualquier lenguaje y cualquier sitio.
Cualquiera que tenga conocimiento
sobre cómo funcionan los lenguajes de
programación a bajo nivel sabrá que
esto es muy muy complicado. Por ello
se han desarrollado infraestructuras
que nos permiten interactuar con los
componentes de manera indirecta. A
este software se le suele llamar “mid-
dleware” (algo así como “software de
en medio”).
Ejemplos famosos de Middleware son
J2EE, que muchos conocerán, y
CORBA, que a muchos les gustaría no
conocer. Ambos son sistemas enormes
y costosos que relegan al programador
a mera herramienta en manos de inge-
nieros, denominados arquitectos, que
conocen su compleja infraestructura.
Pero los sistemas de componentes
también se emplean en software libre y
han dado buenos resultados. Quizás el
más desconocido es UNO, de Universal
Network Objects, el sistema que emplea
OpenOffice, ver Listado [1], y que SUN
desarrolló para su precursor: StarOffice.
PyUNO
Un sistema de componentes con el que
sólo se pueda programar en un
lenguaje no tiene mucha utilidad. Por
eso en OpenOffice se han asegurado de
fomentar la creación de interfaces a
distintos lenguajes de programación.
Podemos acceder a UNO usando
Javascript, Java, Ruby, Perl o Python
(ver Recurso [2]).
PyUNO es el nombre de la interfaz y
podremos encontrarlo sin problemas en
nuestra distribución de Linux. Eviden-
temente, necesitamos también tener
instalado OpenOffice. En este artículo
hemos realizado los programas usando
OpenOffice 2.0, que cambió la interfaz
respecto a la versión 1.0, y la versión
de PyUNO 0.7.0.
Un Ejemplo Rápido
Vamos a crear el famoso «Hola mundo»
con PyUNO. Para ello primero debemos
arrancar OpenOffice con el siguiente
comando desde el directorio donde esté
instalado:
$> ./sofficeU
"-accept=socket,U
INTEGRACIÓNOpenOffice
23PYTHONWWW.LINUX- MAGAZINE.ES
PyUNO: Explota todo el potencial de OpenOffice
Python no hay
más que UNO¿Has visto alguna vez a los brokers de bolsa? ¿Recuerdas sus sofisticados y caros
programas para ver las cotizaciones de las empresas en bolsa en tiempo real? Nos-
otros haremos lo mismo con 70 lineas de código Python, OpenOffice y la tecnología
UNO de OpenOffice. Por José María Ruíz
INTEGRACIÓN OpenOffice
24 PYTHON WWW.LINUX- MAGAZINE.ES
host=localhost,U
port=2002;urp;"
Al arrancar OpenOffice se arranca su
sistema de componentes. Podemos pen-
sar en este proceso como en el
arranque de un servidor, sólo cuando
esté funcionando podrán los clientes
trabajar con él.
Las opciones que pasamos son para
que se cree un socket y se escuche en
localhost en el puerto 2002. Por defecto
OpenOffice no abre el socket, de ma-
nera que no podrán controlar nuestro
OpenOffice sin nuestro consentimiento.
OpenOffice incorpora de serie varios
intérpretes de lenguajes, entre ellos
uno de Python que ya viene preconfig-
urado para poder hacer uso de la libr-
ería UNO. Está junto al resto de eje-
cutables de OpenOffice, así que lo eje-
cutaremos desde allí. El programa que
usaremos se encuentra en el Listado
[2].
El proceso es el siguiente:
• Obtenemos un contexto local (un
sitio donde guardar los datos de la
conexión)
• Arrancamos el componente UnoUrl-
Resolver que nos sirve para acceder
a otro OpenOffice en otro equipo
(en nuestro caso accederemos a
nuestro propio equipo)
• Emplearemos el objeto resolver para
acceder al OpenOffice remoto
• Arrancamos un «Desktop» (escrito-
rio) de OpenOffice (esto es, una
instancia de OpenOffice vacía)
• Arrancamos un SWriter (es decir, el
procesador de textos) en el escrito-
rio
• Obtenemos un cursor, con el que
podremos posicionarnos dentro del
texto
• e insertamos texto en el cursor
El resultado, no muy espectacular,
podemos verlo en la Figura [1]. Ya te-
nemos nuestro «hola mundo» insertado
en SWriter.
¿Demasiado código? Piensa por un
momento lo que estamos haciendo.
01 import uno
02
03 localContext = uno.getComponentContext()
04 resolver = localContext.ServiceManager.createInstanceWithContext
(“com.sun.star.bridge.UnoUrlResolver”, localContext )
05 ctx = resolver.resolve( “uno:socket,host=localhost,port=2002;urp;
StarOffice.ComponentContext” )
06 desktop = ctx.ServiceManager.createInstanceWithContext(
“com.sun.star.frame.Desktop”,ctx)
07 doc =
desktop.loadComponentFromURL(“private:factory/swriter”,”_blank”,0,())
08 cursor = doc.Text.createTextCursor()
09 doc.Text.insertString( cursor, “Hola Mundo”, 0 )
10 ctx.ServiceManager
Listado 1: Programa «Hola Mundo»
01 import uno
02 import random
03 import time
04 import httplib
05 import csv
06
07 class Calc:
08 def __init__(self):
09 self.conecta()
10
11 def conecta (self):
12 self.local = uno.getComponentContext()
13 self.resolver = self.local.ServiceManager.
createInstanceWithContext
(“com.sun.star.bridge.UnoUrlResolver”, self.local)
14 self.context =
self.resolver.resolve(“uno:socket,host=
localhost,port=2002;
urp;StarOffice.ComponentContext”)
15 self.desktop = self.context.ServiceManager.
createInstanceWithContext
(“com.sun.star.frame.Desktop”, self.context)
16 #self.doc = self.desktop.getCurrentComponent()
17 self.doc = self.desktop.loadComponentFromURL
(“private:factory/scalc”,”_blank”,0,())
18 self.hojas = self.doc.getSheets()
19 self.s1 = self.hojas.getByIndex(0)
20
21 def actualiza(self, cotizacion, fila):
22
23 i = 0
24 for entrada in cotizacion:
25 if (i == 0) or (i == 2) or (i ==3):
26 self.s1.getCellByPosition(i,fila).
setString(entrada)
27 else:
28 self.s1.getCellByPosition(i,fila).setValue
(float(entrada))
29
30 i = i + 1
31
32 def getSimbolo(simbolo):
33 c = httplib.HTTPConnection(“finance.yahoo.com”)
34 c.request(“GET”,
”/d/quotes.csv?s=”+simbolo+”&f=sl1d1t1c1ohgv&
e=.csv”)
35 r = c.getresponse()
36 cad = r.read()
37 reader = csv.reader([cad])
38 resultado = []
39 for row in reader:
40 resultado = row
41 return resultado
42
43 if __name__ == ‘__main__’:
44
45 simbolos = [“GOOG”,”MSFT”,”RHAT”]
46
47 c = Calc()
48
49 while(1):
50 i = 0;
51 for s in simbolos:
52 c.actualiza(getSimbolo(s),i)
53 i = i + 1
54
55 time.sleep(10)
Listado 2: «OfficeBroker»
Hemos levantado dos componentes y
hecho acceso remoto a otro OpenOf-
fice. Este segundo OpenOffice puede
estar en una máquina al otro lado del
mundo. Es algo bastante impresionan-
te, pero por el momento poco útil.
Veamos un poco más sobre UNO antes
de realizar un programa más útil.
Arquitectura de UNO
OpenOffice está implementado en
C++. UNO se usa internamente para
realizar cualquier cosa. Básicamente,
OpenOffice no es más que una gran
cantidad de componentes que interac-
túan entre sí. Todo dentro de OpenOf-
fice es un componente, así que
podemos acceder a cualquier parte de
la aplicación, ¡incluso reconstruir
OpenOffice en Python!
Los sistemas de componentes usan
un registro de componentes al que se le
puede pedir que arranque compo-
nentes. El registro localiza el compo-
nente en disco y lo carga en memoria,
de manera que puede ser usado. Las
llamadas a las funciones no se realizan
directamente, sino que se suele
emplear algún sistema no dependiente
de lenguaje o plataforma, como puede
ser XML o un formato ASCII.
El registro también debe ser capaz de
gestionar los recursos que consume el
componente, descargándolo de memo-
ria cuando ya no sea necesario.
Los componentes pueden ser progra-
mados en cualquier lenguaje con el que
se tenga interfaz. Un componente es un
conjunto de ficheros que proporcionan
un servicio. Se acompañan de un
fichero XML que describe su funcional-
idad. Lo mejor es que podemos vincu-
lar ese servicio a algún componente
gráfico, como por ejemplo un botón o
menú.
Comenzaremos por realizar un pro-
grama que funcionará de manera
externa a OpenOffice, y después creare-
mos un componente con él y lo inte-
graremos en OpenOffice.
Nuestro Programa de Stocks
Comencemos con la parte útil, ver Lis-
tado [2]. Vamos a crear un sistema que
nos permita controlar las acciones de
una serie de empresas que están en
bolsa dentro de un índice tecnológico,
el Nasdaq (para algo estamos en una
revista de informática), usando la hoja
de cálculo SCalc y un programa Python.
Nuestro programa accederá usando
Internet a un sitio web donde podrá
recoger los datos en CSV (Valores Sepa-
rados por Comas), los procesará y los
introducirá en SCalc.
Comenzaremos por crear una fun-
ción que recoja el fichero CSV y lo pro-
cese. Lo que hacemos es conectarnos
con la página web finance.yahoo.com.
Yahoo tiene un sitio web bastante
avanzado sobre cotizaciones de bolsa,
y uno de sus servicios nos permite
recoger los datos de cotización de una
empresa en tiempo real en formato
CSV. Sin embargo, Yahoo no nos per-
mitirá acceder a los datos demasiado a
menudo, ya que dispone de un servi-
cio de pago para ello, así que puede
cortarnos el «grifo» en cualquier
momento si hacemos demasiadas con-
sultas por minuto. Por eso recogere-
mos los datos cada 10 segundos. La
función getSimbolo() se encargará de
ello.
Ahora ya tenemos los datos, tenemos
que mandarlos a SCalc. Hemos creado
un objeto llamado Calc para gestionar
el acceso. Hemos metido en el método
constructor (__init__) el código que
conecta con OpenOffice, puesto que
sólo lo haremos una vez. Una hoja de
cálculo posee varias «hojas», así que
tendremos que solicitar una usando el
método getSheets(), que nos devuelve
una lista con las distintas hojas. Dentro
de esta lista usaremos getByIndex()
para seleccionar la primera hoja, que
es la que se ve cuando arrancamos
SCalc.
El método actualiza() admite una
lista con los datos de cotización y
número que representa la fila donde
aparecerá en SCalc. Una hoja de cálculo
se compone de celdas, y éstas tienen un
tipo. La función getCellByPosition() nos
permite acceder a una celda pasándole
la columna y la fila (al revés de lo nor-
mal, así que cuidado).
Una vez localizada la celda, tenemos
varias funciones para poder asignar un
valor:
• setString(): para poner una cadena
• setValue(): para poner un número
• setFormula(): para poner una fór-
mula
El dato cotización es la lista de
parámetros de cotización, pero vienen
dados como cadenas de caracteres. Las
posiciones 0, 2 y 3 son realmente cade-
nas, pero el resto son números. Por eso
tenemos que convertir ciertos valores
al tipo float() mediante la función
float().
El resultado se puede ver en la Figura
[2]. Observamos cómo se abre una ven-
tana de SCalc y se rellena con los val-
INTEGRACIÓNOpenOffice
25PYTHONWWW.LINUX- MAGAZINE.ES
Figura 1: Un documento de Write de OpenOffice con el ineludible
“Hello World” generado a partir de PyUNO.
Figura 2: El programa examina los valores de la bolsa NASDAQ de
Yahoo a intervalos regulares y los inserta en una hoja de cálculo.
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1
Python power 1

Más contenido relacionado

La actualidad más candente

Lenguaje de programación Python
Lenguaje de programación PythonLenguaje de programación Python
Lenguaje de programación PythonKareliaRivas
 
Programacion orientada a objetos python manuel casado martín - universidad ...
Programacion orientada a objetos python   manuel casado martín - universidad ...Programacion orientada a objetos python   manuel casado martín - universidad ...
Programacion orientada a objetos python manuel casado martín - universidad ...Wilson Bautista
 
Parallel Python sistemas operativos avanzados
Parallel Python sistemas operativos avanzadosParallel Python sistemas operativos avanzados
Parallel Python sistemas operativos avanzadosDaniel Muccela
 
Boletín Furnariux FEB 2019
Boletín Furnariux FEB 2019Boletín Furnariux FEB 2019
Boletín Furnariux FEB 2019Alex Floss
 
Tutorial de Python - Pyar
Tutorial de Python - PyarTutorial de Python - Pyar
Tutorial de Python - PyarSergio Vallejo
 

La actualidad más candente (10)

Lenguaje de programación Python
Lenguaje de programación PythonLenguaje de programación Python
Lenguaje de programación Python
 
Programacion orientada a objetos python manuel casado martín - universidad ...
Programacion orientada a objetos python   manuel casado martín - universidad ...Programacion orientada a objetos python   manuel casado martín - universidad ...
Programacion orientada a objetos python manuel casado martín - universidad ...
 
Parallel Python sistemas operativos avanzados
Parallel Python sistemas operativos avanzadosParallel Python sistemas operativos avanzados
Parallel Python sistemas operativos avanzados
 
Python para todos
Python para todosPython para todos
Python para todos
 
1 curso-de-python-introducci-n-a-python
1 curso-de-python-introducci-n-a-python1 curso-de-python-introducci-n-a-python
1 curso-de-python-introducci-n-a-python
 
Unidad V Tutorial de Python
Unidad V Tutorial de PythonUnidad V Tutorial de Python
Unidad V Tutorial de Python
 
Programador Jr. para Python Primera Parte
Programador Jr. para Python Primera ParteProgramador Jr. para Python Primera Parte
Programador Jr. para Python Primera Parte
 
Boletín Furnariux FEB 2019
Boletín Furnariux FEB 2019Boletín Furnariux FEB 2019
Boletín Furnariux FEB 2019
 
Aprendamos python
Aprendamos pythonAprendamos python
Aprendamos python
 
Tutorial de Python - Pyar
Tutorial de Python - PyarTutorial de Python - Pyar
Tutorial de Python - Pyar
 

Destacado

Empirische Überprüfung von Hypothesen zum Einfluss von Social CRM auf die Ver...
Empirische Überprüfung von Hypothesen zum Einfluss von Social CRM auf die Ver...Empirische Überprüfung von Hypothesen zum Einfluss von Social CRM auf die Ver...
Empirische Überprüfung von Hypothesen zum Einfluss von Social CRM auf die Ver...Michael Lindemann
 
Listado de libros para el curso 11
Listado de libros para el curso 11Listado de libros para el curso 11
Listado de libros para el curso 11emitena
 
Avances Audiovisual
Avances AudiovisualAvances Audiovisual
Avances Audiovisualnatalita1
 
Catalogo sierra minera
Catalogo sierra mineraCatalogo sierra minera
Catalogo sierra mineraoptimistaist
 
Social partners - How to integrate social media into contact centres
Social partners  - How to integrate social media into contact centresSocial partners  - How to integrate social media into contact centres
Social partners - How to integrate social media into contact centresBrand Embassy
 
Las controvertidas ratas ciborg de tel aviv
Las controvertidas ratas ciborg de tel avivLas controvertidas ratas ciborg de tel aviv
Las controvertidas ratas ciborg de tel avivJoha Rey
 
Bekerja sebagai Ibadah 2
Bekerja sebagai Ibadah 2Bekerja sebagai Ibadah 2
Bekerja sebagai Ibadah 2Kris Nitihardjo
 
Clin Cancer Res-2012-Lechner-4549-59
Clin Cancer Res-2012-Lechner-4549-59Clin Cancer Res-2012-Lechner-4549-59
Clin Cancer Res-2012-Lechner-4549-59Karolina Megiel
 
Fremont Colleges Sports and Rehabilitation Therapy Students
Fremont Colleges Sports and Rehabilitation Therapy StudentsFremont Colleges Sports and Rehabilitation Therapy Students
Fremont Colleges Sports and Rehabilitation Therapy StudentsSean Lee
 
From Email Bankruptcy to Business Productivity
From Email Bankruptcy to Business ProductivityFrom Email Bankruptcy to Business Productivity
From Email Bankruptcy to Business ProductivityHyperOffice
 

Destacado (20)

Introduccion a-python
Introduccion a-pythonIntroduccion a-python
Introduccion a-python
 
Excel practicas
Excel practicasExcel practicas
Excel practicas
 
Qlikview in the cloud (en)
Qlikview in the cloud (en)Qlikview in the cloud (en)
Qlikview in the cloud (en)
 
Empirische Überprüfung von Hypothesen zum Einfluss von Social CRM auf die Ver...
Empirische Überprüfung von Hypothesen zum Einfluss von Social CRM auf die Ver...Empirische Überprüfung von Hypothesen zum Einfluss von Social CRM auf die Ver...
Empirische Überprüfung von Hypothesen zum Einfluss von Social CRM auf die Ver...
 
Listado de libros para el curso 11
Listado de libros para el curso 11Listado de libros para el curso 11
Listado de libros para el curso 11
 
Avances Audiovisual
Avances AudiovisualAvances Audiovisual
Avances Audiovisual
 
Folleto+iyolo
Folleto+iyoloFolleto+iyolo
Folleto+iyolo
 
Catalogo sierra minera
Catalogo sierra mineraCatalogo sierra minera
Catalogo sierra minera
 
Telepathy (w. w. baggally)
Telepathy (w. w. baggally)Telepathy (w. w. baggally)
Telepathy (w. w. baggally)
 
Social partners - How to integrate social media into contact centres
Social partners  - How to integrate social media into contact centresSocial partners  - How to integrate social media into contact centres
Social partners - How to integrate social media into contact centres
 
Las controvertidas ratas ciborg de tel aviv
Las controvertidas ratas ciborg de tel avivLas controvertidas ratas ciborg de tel aviv
Las controvertidas ratas ciborg de tel aviv
 
CV
CVCV
CV
 
Bekerja sebagai Ibadah 2
Bekerja sebagai Ibadah 2Bekerja sebagai Ibadah 2
Bekerja sebagai Ibadah 2
 
Clin Cancer Res-2012-Lechner-4549-59
Clin Cancer Res-2012-Lechner-4549-59Clin Cancer Res-2012-Lechner-4549-59
Clin Cancer Res-2012-Lechner-4549-59
 
Fremont Colleges Sports and Rehabilitation Therapy Students
Fremont Colleges Sports and Rehabilitation Therapy StudentsFremont Colleges Sports and Rehabilitation Therapy Students
Fremont Colleges Sports and Rehabilitation Therapy Students
 
From Email Bankruptcy to Business Productivity
From Email Bankruptcy to Business ProductivityFrom Email Bankruptcy to Business Productivity
From Email Bankruptcy to Business Productivity
 
Mawi dan ekin
Mawi dan ekinMawi dan ekin
Mawi dan ekin
 
Euroconector
EuroconectorEuroconector
Euroconector
 
Studie "Intranet – Marktübersicht und Trends 2015"
Studie "Intranet – Marktübersicht und Trends 2015"Studie "Intranet – Marktübersicht und Trends 2015"
Studie "Intranet – Marktübersicht und Trends 2015"
 
Los francos
Los francosLos francos
Los francos
 

Similar a Python power 1

Parallel python sistemas operativos avanzados
Parallel python sistemas operativos avanzadosParallel python sistemas operativos avanzados
Parallel python sistemas operativos avanzadosDaniel Muccela
 
Python basic slides for beginners to learn python
Python basic slides for beginners to learn pythonPython basic slides for beginners to learn python
Python basic slides for beginners to learn pythonnotelodigo5
 
python-para-todos.pdf
python-para-todos.pdfpython-para-todos.pdf
python-para-todos.pdfJaviMartin21
 
Python para todos
Python para todosPython para todos
Python para todosErik Gur
 
python-para-todos.pdf
python-para-todos.pdfpython-para-todos.pdf
python-para-todos.pdfRafalJMalave
 
Python para todos
Python para todosPython para todos
Python para todossebas145713
 
Python_para_todos.pdf
Python_para_todos.pdfPython_para_todos.pdf
Python_para_todos.pdfssuser626fe4
 
Clase 1- Fundamentos de programacion en Phyton.pptx
Clase 1- Fundamentos de programacion en Phyton.pptxClase 1- Fundamentos de programacion en Phyton.pptx
Clase 1- Fundamentos de programacion en Phyton.pptxVeronica Freire
 
Python y la POO, en una clase, UNNe-Corrientes
Python y la POO, en una clase, UNNe-CorrientesPython y la POO, en una clase, UNNe-Corrientes
Python y la POO, en una clase, UNNe-Corrientesalexis ibarra
 
Jupyter e IPython para manipulación de datos
Jupyter e IPython para manipulación de datosJupyter e IPython para manipulación de datos
Jupyter e IPython para manipulación de datosSoftware Guru
 
Resumen python
Resumen pythonResumen python
Resumen pythonhedaro
 
Clase 2 - Introducción a la programación con Python I.pptx
Clase 2 - Introducción a la programación con Python I.pptxClase 2 - Introducción a la programación con Python I.pptx
Clase 2 - Introducción a la programación con Python I.pptxjgs07
 
Instituto de capacitacion futuro incaf
Instituto de capacitacion futuro incafInstituto de capacitacion futuro incaf
Instituto de capacitacion futuro incafMigueloChavez
 
Mi lenguaje de preferencia
Mi lenguaje de preferenciaMi lenguaje de preferencia
Mi lenguaje de preferenciaAlexanderMBaez
 
1. Presentación e instalación de Python.pdf
1. Presentación e instalación de Python.pdf1. Presentación e instalación de Python.pdf
1. Presentación e instalación de Python.pdfJhonJairoMorenoDuart
 

Similar a Python power 1 (20)

Parallel python sistemas operativos avanzados
Parallel python sistemas operativos avanzadosParallel python sistemas operativos avanzados
Parallel python sistemas operativos avanzados
 
Python basic slides for beginners to learn python
Python basic slides for beginners to learn pythonPython basic slides for beginners to learn python
Python basic slides for beginners to learn python
 
python-para-todos.pdf
python-para-todos.pdfpython-para-todos.pdf
python-para-todos.pdf
 
Python para todos
Python para todosPython para todos
Python para todos
 
Python para Todos
Python para TodosPython para Todos
Python para Todos
 
python-para-todos.pdf
python-para-todos.pdfpython-para-todos.pdf
python-para-todos.pdf
 
Libro python para todos
Libro   python para todosLibro   python para todos
Libro python para todos
 
Python para todos
Python para todosPython para todos
Python para todos
 
Python_para_todos.pdf
Python_para_todos.pdfPython_para_todos.pdf
Python_para_todos.pdf
 
Python_para_todos.pdf
Python_para_todos.pdfPython_para_todos.pdf
Python_para_todos.pdf
 
Clase 1- Fundamentos de programacion en Phyton.pptx
Clase 1- Fundamentos de programacion en Phyton.pptxClase 1- Fundamentos de programacion en Phyton.pptx
Clase 1- Fundamentos de programacion en Phyton.pptx
 
Python y la POO, en una clase, UNNe-Corrientes
Python y la POO, en una clase, UNNe-CorrientesPython y la POO, en una clase, UNNe-Corrientes
Python y la POO, en una clase, UNNe-Corrientes
 
Sesion8_Python.pptx
Sesion8_Python.pptxSesion8_Python.pptx
Sesion8_Python.pptx
 
Jupyter e IPython para manipulación de datos
Jupyter e IPython para manipulación de datosJupyter e IPython para manipulación de datos
Jupyter e IPython para manipulación de datos
 
Yudy Centeno M
Yudy Centeno MYudy Centeno M
Yudy Centeno M
 
Resumen python
Resumen pythonResumen python
Resumen python
 
Clase 2 - Introducción a la programación con Python I.pptx
Clase 2 - Introducción a la programación con Python I.pptxClase 2 - Introducción a la programación con Python I.pptx
Clase 2 - Introducción a la programación con Python I.pptx
 
Instituto de capacitacion futuro incaf
Instituto de capacitacion futuro incafInstituto de capacitacion futuro incaf
Instituto de capacitacion futuro incaf
 
Mi lenguaje de preferencia
Mi lenguaje de preferenciaMi lenguaje de preferencia
Mi lenguaje de preferencia
 
1. Presentación e instalación de Python.pdf
1. Presentación e instalación de Python.pdf1. Presentación e instalación de Python.pdf
1. Presentación e instalación de Python.pdf
 

Último

El uso de las tic en la vida ,lo importante que son
El uso de las tic en la vida ,lo importante  que sonEl uso de las tic en la vida ,lo importante  que son
El uso de las tic en la vida ,lo importante que son241514984
 
El uso de las TIC's en la vida cotidiana.
El uso de las TIC's en la vida cotidiana.El uso de las TIC's en la vida cotidiana.
El uso de las TIC's en la vida cotidiana.241514949
 
Hernandez_Hernandez_Practica web de la sesion 11.pptx
Hernandez_Hernandez_Practica web de la sesion 11.pptxHernandez_Hernandez_Practica web de la sesion 11.pptx
Hernandez_Hernandez_Practica web de la sesion 11.pptxJOSEMANUELHERNANDEZH11
 
Plan Sarmiento - Netbook del GCBA 2019..
Plan Sarmiento - Netbook del GCBA 2019..Plan Sarmiento - Netbook del GCBA 2019..
Plan Sarmiento - Netbook del GCBA 2019..RobertoGumucio2
 
Mapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMidwarHenryLOZAFLORE
 
El uso delas tic en la vida cotidiana MFEL
El uso delas tic en la vida cotidiana MFELEl uso delas tic en la vida cotidiana MFEL
El uso delas tic en la vida cotidiana MFELmaryfer27m
 
La era de la educación digital y sus desafios
La era de la educación digital y sus desafiosLa era de la educación digital y sus desafios
La era de la educación digital y sus desafiosFundación YOD YOD
 
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxMedidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxaylincamaho
 
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptxCrear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptxNombre Apellidos
 
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptxGoogle-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptxAlexander López
 
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxEl_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxAlexander López
 
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptTEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptJavierHerrera662252
 
tics en la vida cotidiana prepa en linea modulo 1.pptx
tics en la vida cotidiana prepa en linea modulo 1.pptxtics en la vida cotidiana prepa en linea modulo 1.pptx
tics en la vida cotidiana prepa en linea modulo 1.pptxazmysanros90
 
Segunda ley de la termodinámica TERMODINAMICA.pptx
Segunda ley de la termodinámica TERMODINAMICA.pptxSegunda ley de la termodinámica TERMODINAMICA.pptx
Segunda ley de la termodinámica TERMODINAMICA.pptxMariaBurgos55
 
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfPARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfSergioMendoza354770
 
Presentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadPresentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadMiguelAngelVillanuev48
 
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxLAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxAlexander López
 
dokumen.tips_36274588-sistema-heui-eui.ppt
dokumen.tips_36274588-sistema-heui-eui.pptdokumen.tips_36274588-sistema-heui-eui.ppt
dokumen.tips_36274588-sistema-heui-eui.pptMiguelAtencio10
 
R1600G CAT Variables de cargadores en mina
R1600G CAT Variables de cargadores en minaR1600G CAT Variables de cargadores en mina
R1600G CAT Variables de cargadores en minaarkananubis
 
GonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptxGonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptx241523733
 

Último (20)

El uso de las tic en la vida ,lo importante que son
El uso de las tic en la vida ,lo importante  que sonEl uso de las tic en la vida ,lo importante  que son
El uso de las tic en la vida ,lo importante que son
 
El uso de las TIC's en la vida cotidiana.
El uso de las TIC's en la vida cotidiana.El uso de las TIC's en la vida cotidiana.
El uso de las TIC's en la vida cotidiana.
 
Hernandez_Hernandez_Practica web de la sesion 11.pptx
Hernandez_Hernandez_Practica web de la sesion 11.pptxHernandez_Hernandez_Practica web de la sesion 11.pptx
Hernandez_Hernandez_Practica web de la sesion 11.pptx
 
Plan Sarmiento - Netbook del GCBA 2019..
Plan Sarmiento - Netbook del GCBA 2019..Plan Sarmiento - Netbook del GCBA 2019..
Plan Sarmiento - Netbook del GCBA 2019..
 
Mapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptx
 
El uso delas tic en la vida cotidiana MFEL
El uso delas tic en la vida cotidiana MFELEl uso delas tic en la vida cotidiana MFEL
El uso delas tic en la vida cotidiana MFEL
 
La era de la educación digital y sus desafios
La era de la educación digital y sus desafiosLa era de la educación digital y sus desafios
La era de la educación digital y sus desafios
 
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxMedidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
 
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptxCrear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
 
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptxGoogle-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
 
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxEl_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
 
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptTEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
 
tics en la vida cotidiana prepa en linea modulo 1.pptx
tics en la vida cotidiana prepa en linea modulo 1.pptxtics en la vida cotidiana prepa en linea modulo 1.pptx
tics en la vida cotidiana prepa en linea modulo 1.pptx
 
Segunda ley de la termodinámica TERMODINAMICA.pptx
Segunda ley de la termodinámica TERMODINAMICA.pptxSegunda ley de la termodinámica TERMODINAMICA.pptx
Segunda ley de la termodinámica TERMODINAMICA.pptx
 
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfPARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
 
Presentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadPresentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidad
 
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxLAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
 
dokumen.tips_36274588-sistema-heui-eui.ppt
dokumen.tips_36274588-sistema-heui-eui.pptdokumen.tips_36274588-sistema-heui-eui.ppt
dokumen.tips_36274588-sistema-heui-eui.ppt
 
R1600G CAT Variables de cargadores en mina
R1600G CAT Variables de cargadores en minaR1600G CAT Variables de cargadores en mina
R1600G CAT Variables de cargadores en mina
 
GonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptxGonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptx
 

Python power 1

  • 1. W W W . L I N U X - M A G A Z I N E . E S 8413042594529 00006 BÁSICO Introducción a Python con ejemplos prácticos Denis Babenko - 123RF.com MANUAL PRÁCTICO DVD GRATIS Debian 6 17PROYECTOS COMPLETOS Y FUNCIONALES Tu Guía Práctica Aprende de desarrolladores profesionales y de sus ejemplos del mundo real ■ Automatiza formularios web ■ Integra Python con Java, .Net y Qt ■ Amplía Open/LibreOffice ■ Crea y manipula PDFs ■ Maneja grandes volúmenes de datos ENERO 2012 Península y Baleares 6,95 € Canarias 7,05 € Especial 06 INFRAESTRUCTURAS Explota los motores tras Facebook, Google y Twitter 48 MÓDULOS Descubre cómo programar para 3D y a manipular datos e imágenes 59
  • 2. En la tienda de Linux Magazine (www.linux-magazine.es/tienda) vendemos revistas y libros que pue- den ser de interés a nuestros lectores. Recuerda también que con una subscripción Digital o Club, podrás acceder a las ofertas (www.linux-magazine.es/digital/ofertas) de Linux Magazine donde pue- des conseguir software, gadgets, libros y servicios. Este mes en nuestra tienda... Manual LPIC-1 El único manual en castellano para la certificación com- pleta LPIC-1 (exámenes 101 y 102). Más de 250 páginas de ejemplos reales tomados de ambos exámenes expli- cados en todo detalle con ejercicios para prácticas y sus soluciones. Preparado para el nuevo programa que entra en vigor a partir del 2009, aprobado y recomendado por LPI Inter- national y con la garantía de Linux Magazine. ■ ”La guía perfecta en castellano para preparar el exa- men para cualquier persona que tenga conocimien- tos de Linux.” ■ ”Se ciñe muy bien a los objetivos del nivel 1 de LPI (LPIC-1) actualizados en Abril de este año, cosa que es de agradecer.” ■ ”Un avance muy importante en el desarrollo de los programas de certificación LPI en España.” www.lpi.org.es Consíguelo en nuestra tienda.
  • 3. DVD/EDITORIALDebian 6 3PYTHONWWW.LINUX- MAGAZINE.ES Especial Python En el DVD de este especial encontrarás la versión Live de la última iteración estable de Debian [2] para arquitecturas de 32 bits (la más universal). Al ser Debian la más completa de las distros GNU/Linux, podrás encontrar en sus repositorios todas las herramientas, módulos e infraestructuras que necesita- rás para seguir los artículos de este especial. DVD: Debian 6.0.3 Aunque la norma en el sangrado de código en Python es que las tabulaciones a principio de línea sean múltiplos de cua- tro espacios, para favorecer la legibilidad de los listados en este especial, cada tabu- lación se ha reducido a un solo espacio. De esta manera, código que normal- mente se escribiría como: for i in range (1, 5): if ((i % 2) == 0): print i,” es par” else: print i,” es impar” Se reproduce así en los artículos: for i in range (1, 5): if ((i % 2) == 0): print i,” es par” else: print i,” es impar” A pesar de ser técnicamente correcto, animamos a que, si se transcribe código para su ejecución, se utilice la conven- ción de los 4 espacios. En todo caso, todo el código está dispo- nible, con su formato convencional, en el sitio de Linux Magazine en [1]. Formato del Código en este Especial [1] Todo el código de este especial: http:// www.linux-magazine.es/Magazine/ Downloads/Especiales/06_Python [2] Debian: http://www.debian.org/index. es.html Recursos Bautizado en honor al grupo de cómicos británicos Monty Python, Guido Von Rossum concibió este lenguaje en los años 80, comenzando su implementación en 1989. Gra- cias a su sencillez y a la idea de que el código bello se consigue siendo explícito y simple, Python se ha convertido en sus poco más de 20 años de exis- tencia en el lenguaje favorito para scripts, aun- que también para grandes infraestructuras y aplicaciones. Así, la mayor parte de los servicios de Goo- gle y Facebook se construyeron utilizando Python, las aplicaciones de diseño Inkscape o Blender (entre muchas otras) utilizan un motor Python para sus plugins. También se utiliza ampliamente en la investigación en entidades que van desde CERN hasta la NASA. Además, su clara y bien pensada sintaxis, su modularidad y su sobresaliente rendi- miento – a pesar de ser interpretado – hacen de Python un excelente lenguaje educativo, ideal para enseñar programación del mundo real a todos los niveles. Con este especial pretendemos que el lector pueda descubrir Python desde el principio, creando para ello artículos que abordan desde tutoriales introductorios, hasta programación de alto nivel y para usos avanzados. Cada sección viene con varios ejemplos prácticos, código y soluciones extraídas del mundo real. ■
  • 4. CONTENIDO Python 01 4 PYTHON WWW.LINUX- MAGAZINE.ES 06 Primeros Pasos Python es un lenguaje potente, seguro, flexible… pero sobre todo sen- cillo y rápido de aprender, que nos permite crear todo lo que necesitamos en nuestras aplicaciones de forma ágil y eficaz 10 Álbum Fotográfico Siguiendo con nuestro paseo por Python, vemos características básicas, y concretamente en este artículo, el tratamiento de ficheros creando un programa para la ordenación de colec- ciones de fotos. 15 Desparasitando Serpientes Da igual lo buenos programadores que seamos, tarde o temprano dare- mos con ese BUG que será nuestro peor enemigo. Veamos cómo pode- mos emplear herramientas para derro- tarlo con mayor facilidad. 19 Sin Nombre Python es un lenguaje de programa- ción multiparadigma, y las funciones lambda son parte fundamental de él, aunque como veremos, existen bue- nas razones para no abusar de ellas. 23 Python no hay más que UNO ¿Has visto alguna vez a los brokers de bolsa y sus sofisticados y caros pro- gramas para ver las cotizaciones de las empresas en bolsa en tiempo real? Nosotros haremos lo mismo con Python, OpenOffice y la tecnología UNO de OpenOffice. 28 Cuando los Mundos Chocan Os descubrimos Jython, la forma mas sencilla de desarrollar vuestras aplica- ciones Java como si las programárais con Python. 33 Limpieza Total AJAX es la palabra de moda, Google usa AJAX, Yahoo usa AJAX… todo el mundo quiere usar AJAX pero ¿lo usas tú? y más importante aún ¿qué demonios es AJAX? 39 De Serpientes y Primates .NET está avanzando, y Python no se ha quedado atrás. En lugar de comba- tirlo, ha entrado en simbiosis con ella. Con Ironpython podremos hacer uso de toda la potencia de .NET desde nuestro lenguaje favorito. 43 ¡Desarrollo Rápido! Ha llegado el cliente y te lo ha dejado claro: necesita el programa para ayer. Ha surgido un problema enorme y es necesario resolverlo en tiempo récord. La desesperación se palpa en el ambiente y todos los ojos miran a tu persona. Devuelves una mirada de confianza y dices con tono tranquilo: «No te preocupes, tengo un arma secreta para acabar con el problema». 03 DVD Debian 6 82 Información de Contacto Otras Secciones Introducción Avanzado Integración Integración
  • 5. CONTENIDOPython 01 5PYTHONWWW.LINUX- MAGAZINE.ES 48 Pyramid Uno de los rivales de peso de Django está creciendo en popularidad poco a poco. 52 Guitarrazos Los creadores del proyecto Django nos hablan de la formación de la Django Software Foundation y mostramos cómo comenzar con esta infraestruc- tura web. 55 Seriales Hacer que distintos servicios se comu- niquen entre ellos es todo un pro- blema que Facebook ha tratado de solucionar con Thrift. 59 Cuaderno de Bitácora ¿Te acuerdas de cuando cambiaste la versión de Firefox por última vez? ¿ y de por qué instalaste ese programa tan raro que parece no servir para nada ? Yo tengo mala memoria, así que uso un cuaderno de bitácora. 65 Gráficas 3D Crear gráficos 3D no es nada difícil en Python... sobre todo si tenemos a mano la librería VTK. 69 Vigilantes del planeta ¿Quién no ha querido alguna vez sen- tirse como esos informáticos de la NASA en su centro de control? Hoy nos construiremos el nuestro y contro- laremos el planeta y sus alrededores. 73 Enredados Podemos automatizar comandos y programas gráficos, ¿por qué no auto- matizar la interacción con páginas web? En este artículo crearemos un pequeño script que puede ahorrarnos mucho trabajo con el ratón. 77 ReportLab Hoy en día se hace imprescindible dis- poner de herramientas que permitan generar informes en PDF de alta cali- dad rápida y dinámicamente. Existen diferentes herramientas para esta fina- lidad, entre ellas cabe destacar Repor- tLab, biblioteca gratuita que permite crear documentos PDF empleando como lenguaje de programación Python. Ver información en pág. 3 VERSIÓN DVDGNOME LIVE Infraesctructuras Librerías Librerías
  • 6. INTRODUCCIÓN Primeros Pasos 6 PYTHON WWW.LINUX- MAGAZINE.ES Para empezar, debemos saber por qué Python es interesante, por qué es tan famoso y cada vez más utilizado. Mirando un poco por Internet se pueden encontrar multitud de aplicaciones que nos muestran parte de las capacidades de este lenguaje de alto nivel. Vamos a enumerar algunas de sus sorprendentes características: • Orientado a objetos – Esto no significa que sea exclusivamente orientado a objetos, podemos utilizarlo como quera- mos, aunque le sacaremos más prove- cho si usamos su implementación de OOP (Programación Orientada a Obje- tos). • Libre y gratuito – Desde la red, pode- mos descargar el interprete y su código fuente, y al ser un lenguaje de script, viene con la mayoría de las distros GNU/Linux de manera predeterminada, siendo posible ver el código de una enorme parte del software desarrollado para Python. • Portable – Al ser interpretado, podemos ejecutar nuestros programas en cual- quier S.O. y/o arquitectura simplemente teniendo instalado previamente el intér- prete en nuestro ordenador . • Potente – Realizar un programa bajo este lenguaje seguramente nos costaría entre la mitad o la cuarta parte del tiempo que tardaríamos en desarrollar el mismo programa en C/C++ o Java. • Claro – Puede que ésta sea una de las características más alabadas de Python: Los programas escritos en este lenguaje tienden a ser fáciles de comprender y, por tanto, de mantener por terceros. Una enorme ventaja frente a lenguajes como C o Perl. Pero veamos una breve comparativa con otros lenguajes: Hola Mundo en C: main () { printf(“Hola Mundo”); } Hola Mundo en Java: public static void U main(String args[]) { System.out.println(“Hola U Mundo”); } Hola Mundo en Python: print “Hola Mundo” Aunque los “Hola Mundo” no son muy indicativos de nada, nótese la ausencia de puntos y comas, llaves, declaración de fun- ciones y otros “trastos” que entorpecen el código. Esto es incluso más obvio en pro- gramas más largos. Python dispone de otras características que lo convierten en el lenguaje favorito de una comunidad de desarrolladores cada vez más amplia. Por ejemplo, per- mite la declaración dinámica de varia- bles, es decir, no tenemos que declarar las variables ni tener en cuenta su tamaño, ya que son completamente diná- micas. Además, dispone de un gestor de memoria que, de manera similar al de java, se encargará de liberar memoria de objetos no utilizados. Sin embargo, y al igual que Java, no permite usar la memo- ria a bajo nivel como C, con el que nos podíamos referir a zonas de memoria directamente. Además se puede combinar con otros múltiples lenguajes de programación. Podemos mezclar en nuestras aplicaciones Python y Java (Jython – ver el artículo al respecto en la página 28 de este especial), por ejemplo. O Python con C/C++, lo cual hace que resulte mas potente si cabe. Python también cuenta con una amplia biblioteca de módulos que, al estilo de las bibliotecas en C, permiten un desarrollo rápido y eficiente. La sencillez de Python también ayuda a que los programas escritos en este lenguaje sean muy sintéticos. Como podemos ver en el ejemplo “Hola Mundo” anterior, la simplicidad llega a ser asombrosa. Si este programa ya supone ahorrarte 4 ó 5 líneas de código, con una sintaxis tan sencilla y ordenada podemos imaginar que un pro- grama de 1000 líneas en Java, en Python se redujeran unas 250. Python es un lenguaje potente, seguro, flexi- ble… pero sobre todo sencillo y rápido de aprender, que nos permite crear todo lo que necesitamos en nuestras aplicaciones de forma ágil y eficaz. Por José María Ruíz Aprende a programar con este lenguaje de programación multiplataforma Primeros Pasos AnitaPatterson-morguefile.com
  • 7. Uso Para empezar a matar el gusanillo, pode- mos ir haciendo algunas pruebas intere- santes. Vayamos al intérprete Python. Para ello, basta con escribir ‘python’ en el prompt de una terminal (por ejemplo, Bash en GNU/Linux o Powershell en Win- dows) y probar nuestro “Hola Mundo”: >>> print ‘Hola Mundo’ Hola Mundo Ahora probemos a utilizar algunas varia- bles: >>> suma = 15 + 16 >>> >>> print ‘el resultado de la U suma es: ‘, suma el resultado de la suma es: 31 Es recomendable trastear un poco con esto antes de ponernos a programar algo más complicado, ya que de esta manera es más sencillo hacerse con la sintaxis mucho más rápidamente viendo los resultados de cada prueba. Veamos ahora alguna propiedad intere- sante de Python. Los ficheros en Python no tienen por qué llevar extensión nin- guna, pero seguramente querremos tener- los diferenciados del resto de ficheros que tengamos. Por ello se suele utilizar la extensión .py. Pero ¿cómo sabe el sistema que intér- prete utilizar cuando queramos ejecutar nuestros scripts? Sencillo: Imaginemos que tenemos un ejemplo.py, al ser un lenguaje tipo script, debemos poner #! seguido de la ruta del intérprete de Python en la cabe- cera del fichero. De esta manera, y dándole permisos de ejecución (chmod +x ejem- plo.py en GNU/Linux), obtenemos un pro- grama listo para su ejecución. Si nuestro intérprete Python se halla en /usr/bin/, el contenido de ./ejemplo.py quedaría, pues, como sigue: #! /usr/bin/python print ‘Hola Mundo’ Después de toda la introducción técnica va siendo hora de que veamos cómo es el for- mato de los programas en Python. Esto es importante porque, mientras la norma en la mayoría de los lenguajes es dejar al pro- gramador la decisión de la manera en que deben ser formateados los archivos fuente, en Python es obligatorio hacerlo de cierta forma. En Python todo se hace de un solo modo, de hecho es parte de su filosofía: “Solo Hay Una Manera de Hacer Las Cosas”. Comencemos con lo más simple en todo lenguaje, la asignación a una variable: cantidad = 166.386 (Para los que no lo recuerden, 166,386 era la cantidad de pesetas que hay en un euro). Lo primero que hay que apreciar es que no se usa el ;. Esto es una característica de las muchas que hacen a Python diferente. Una sentencia acaba con el retorno de carro, aunque el ; se puede usar cuando dos sentencias están en la misma línea: cant = 166.386; ptas = 3000 Como es un lenguaje dinámico, no hay que declarar el tipo de las variables, pero una vez que una variable ha sido definida (lo que se hace asignándole un valor), esa variable guarda su tipo y no lo cambiará a lo largo de la ejecución del programa. También tenemos a nuestra disposición los operadores habituales de otros lengua- jes: +, -, *, /, etc. Y una vez que sabemos cómo manejar operadores y asignaciones, se pueden hacer cosas útiles, pero sólo de manera lineal. Para que la ejecución no sea lineal necesitamos los bucles y los condi- cionales. El tema de los bucles en Python es algo especial. Puede que estemos acostumbra- dos a los que son de tipo C: for (a = 1; a < 10; a++) U printf(“%dn”,a); Sin embargo, en Python se toma un enfo- que funcional prestado de otros lenguajes como Lisp o Haskell. Se utiliza una fun- ción especial llamada «range». La función «range» genera una lista de números: range(1,10) generará una ristra de números del 1 al 9. De esta manera, podemos utilizar una fun- ción range para crear un bucle for en Python de la siguiente manera: for i in range(1,10) Este bucle iteraría con i desde 1 a 9, ambos inclusive. La versión del bucle while en Python es más normal… while(<condición>) al igual que if… if (<condición>) ¿Por qué no he puesto cuerpos de ejemplo en esos bucles? Pues porque ahora viene otra novedad. En Python no se usan las famosas { y } para delimitirlas. Se decidió (y no a todo el mundo le gusta) que se usa- ría la posición como delimitador. Esto, así, suena algo extraño, pero si se ve es mucho más sencillo: >>> cantidad = 2 >>> for i in range(1,10): print cantidad*i Comencemos mirando a ese :. Los dos puntos marcan el inicio de un bloque de código Python. Ese bloque aparecerá en bucles, funciones o métodos. Si nos fija- mos bien en la sangría de la siguiente línea, vemos una serie de espacios (logra- dos pulsando la tecla TABULADOR) y una sentencia. Esos espacios son vitales, ya que marcan la existencia de un bloque de código. Además, son obligatorios. Este es uno de los hechos más contro- vertidos de Python, pero también mejora mucho la legibilidad del código. Sólo existe una manera de escribir Python, así que todo el código Python se parece y es más fácil de entender. El bloque acaba cuando desaparecen esos espacios: >>> for i in range(1,10): ... print cantidad*i ... cantidad = cantidad + 1 ... >>> Funciones y Objetos Ya tenemos las piezas fundamentales para entender las funciones y los objetos. La declaración de una función en Python tiene una sintaxis muy simple: def nombre_funcion U (<lista argumentos>): <CUERPO> Fácil ¿no? Al igual que las variables, a los argumentos no se les asignan tipos. Exis- ten muchas posibilidades en los argumen- tos, pero los veremos más tarde. De momento examinemos un ejemplo sim- ple: INTRODUCCIÓNPrimeros Pasos 7PYTHONWWW.LINUX- MAGAZINE.ES W W W. L I N U X - M A G A Z I N E . E S
  • 8. Estructuras de Datos Una de las razones por las que los progra- mas scripts de Python resultan tan poten- tes, es que nos permiten manejar estructu- ras de datos muy versátiles de manera muy sencilla. En Python estas estructuras son las Listas y los Diccionarios (también llamados Tablas Hash). Las listas nos permiten almacenar una cantidad ilimitada de elementos del mismo tipo. Esto es algo inherente a casi todos los programas, así que Python las incorpora de fábrica. Las listas de Python también vienen provistas de muchas más opciones que sus semejantes en otros lenguajes. Por ejemplo, vamos a definir una lista que guarde una serie de palabras: >>> a = [“Hola”, “Adios”, U “Buenas Tardes”] >>> a [‘Hola’, ‘Adios’, U ‘Buenas Tardes’] Python indexa comenzando desde 0, de manera que ‘Hola’ es el elemento 0, ‘Adios’ el 1 y ‘Buenas Tardes’ el 2, y la longitud de la lista es 3. Podemos comprobarlo de esta forma: >>> a[1] ‘Adios’ >>> len(a) 3 Es posible añadir elementos a las listas de varias maneras. Si miramos el Listado 2, veremos la más sencilla. Las listas también se pueden comportar como una Pila, con las operaciones append y pop. Con insert introducimos un elemento en la posición especificada (recuerda que siempre comenzamos a contar desde 0). La facili- dad con la que Python trata las listas nos permite usarlas para multitud de tareas, lo que simplificará mucho nuestro trabajo. A pesar de su potencia, las listas no pue- den hacerlo todo, existiendo otra estruc- tura que rivaliza con ellas en utilidad, los Diccionarios. Mientras las listas nos permi- ten referenciar a un elemento usando un número, los diccionarios nos permiten hacerlo con cualquier otro tipo de dato. Por ejemplo, con cadenas, de hecho, casi siempre con cadenas, de ahí que su nom- bre sea diccionario (véase el Listado 3). Las listas y los diccionarios se pueden mezclar: diccionarios de listas, listas de diccionarios, diccionarios de listas de dic- cionarios, etc. Ambas estructuras combi- nadas poseen una enorme potencia. Algoritmos + Estructuras de Datos = Programas Ahora nos toca poner todo esto en prác- tica. Lo normal es hacer un programa sen- cillo. Pero en lugar de eso vamos a imple- mentar algo que sea creativo. Este pro- grama es el que se usa en el libro “La prác- tica de la programación” de Pike y Kernig- han para ilustrar cómo un buen diseño sobrepasa al lenguaje que usemos para eje- >>> def imprime (texto): ... print texto >>> imprime(“Hola mundo”) Hola mundo >>> Vuelve a ser sencillo. ¿Y los objetos? Pues también son bastante simples de imple- mentar. Podemos ver un ejemplo en el Lis- tado 1. Con class declaramos el nombre de la clase, y los def de su interior son los métodos. El método __init__ es el cons- tructor, donde se asignan los valores inicia- les a las variables. __init__ es un método estándar y predefinido, lo que quiere decir que tendremos que usar ése y no otro para inicializar el objeto. Todos los métodos, aunque no acepten valores, poseen un parámetro self. Este es otro punto contro- vertido en Python; self es obligatorio, pero no se usa al invocar el método. ¿Cómo se crea el objeto? >>> a = Objeto(20) Es como llamar a una función. A partir de este momento a es una instancia de Objeto, y podemos utilizar sus métodos: >>> print a.getCantidad() 20 >>> a.setCantidad(12) >>> print a.getCantidad() 12 No hay que preocuparse por la administra- ción de la memoria del objeto ya que, cuando a no apunte al objeto, el gestor de memoria liberará su memoria. Ya tenemos las bases para construir algo interesante. Por supuesto, nos dejamos infinidad de cosas en el tintero, pero siem- pre es mejor comenzar con un pequeño conjunto de herramientas para empezar a usarlas. En todo caso, tendremos tiempo de profundizar en los siguientes artículos de este especial. INTRODUCCIÓN Primeros Pasos 8 PYTHON WWW.LINUX- MAGAZINE.ES 01 class Objeto: 02 def __init__ (self, cantidad): 03 self.cantidad = cantidad 04 05 def getCantidad(self): 06 return self.cantidad 07 08 def setCantidad(self, cantidad): 09 self.cantidad = cantidad Listado 1: Una Clase Sencilla 01 >>> dic = {} 02 >>> dic[“Perro”] = “hace guau guau” 03 >>> dic[“Gato”] = “hace miau miau” 04 >>> dic[“Pollito”] = “hace pio pio” 05 >>> dic 06 {‘Perro’: ‘hace guau guau’, 07 ‘Gato’: ‘hace miau miau’, 08 ‘Pollito’: ‘hace pio pio’} 09 >>> dic[“Perro”] 10 ‘hace guau guau’ Listado 3: Ejemplo Diccionario 01 >>> b = [ 1 , 2 , 1 ] 02 >>> b.append(3) 03 >>> b.append(4) 04 >>> b 05 [1 , 2 , 1 , 3 , 4 ] 06 >>> b.remove(1) 07 >>> b 08 [2, 1, 3, 4] 09 >>> b.pop() 10 4 11 >>> b 12 [2, 1, 3] 13 >>> b.insert(1,57) 14 >>> b 15 [2, 57, 1, 3] 16 >>> b.append(1) 17 >>> b 18 [2, 57, 1, 3, 1] 19 >>> b.count(1) 20 2 21 >>> b.index(57) 22 1 23 >>> b.sort() 24 >>> b 25 [1, 1, 2, 3, 57] 26 >>> b.reverse() 27 >>> b 28 [57, 3, 2, 1, 1] Listado 2: Adición y Eliminación de Elementos de Lista
  • 9. cutarlo. En el libro se implementa el diseño en C, C++, Java, Perl y AWK. Nosotros lo haremos en Python (ver Listado 4). El programa acepta un texto como entrada y genera un texto como salida, pero este segundo texto no tiene sentido. Lo que queremos hacer es generar texto sin sentido pero con estructuras que sí lo tengan. Puede parecer algo muy complicado, pero no lo es tanto si usamos la técnica de cadenas de Markov. La idea es coger 2 palabras, elegir una palabra que suceda a cualquiera de las dos y reemplazar la primera por la segunda y la segunda por la palabra escogida. De esta manera vamos generando un texto que, aunque carece de sentido, normalmente se corresponde con la estructura de un texto normal aunque disparatado. Para hacer las pruebas es recomendable conseguir un texto de gran tamaño. En tex- tos pequeños no surtirá tanto efecto. En el proyecto Gütenberg podemos conseguir infinidad de textos clásicos de enorme tamaño en ASCII. Pero somos conocedores de que no todo el mundo entiende el idioma anglosajón, así que en lugar de ir al proyecto Gütenberg, podemos coger cual- quier texto que queramos modificar, por ejemplo, alguna noticia de política de un diario digital o alguna parrafada de algún blog. Este programa es interesante porque per- mitirá utilizar las estructuras de datos que Python implementa, en particular en los diccionarios, que generan una tabla donde los índices serán cadenas de texto. Veamos cómo funciona. Lo primero es ir introduciendo en el diccionario dos prefi- jos como índice y las palabras que les siguen en el texto dentro de una lista refe- renciada por ellos. Eso es un diccionario con dos palabras como índice que contiene una lista: DICCIONARIO[ palabra 1, U palabra 2] -> U LISTA[palabra,...] O sea, si tenemos las palabras “La gente está … La gente opina”, crearemos un dic- cionario de la siguiente forma: >>> dict[‘La’, ‘gente’] = U [‘está’] >>> dict[‘La’, ‘gente’].U append(‘opina’) >>> dict[‘La’, ‘gente’] [‘está’,’opina’] Vamos haciendo esto de manera sucesiva con todos los conjuntos de dos palabras, y obtendremos un diccionario en el que muchas entradas referenciarán a una lista de más de un elemento. La magia aparece cuando generamos el texto, puesto que lo que hacemos es comenzar por las dos primeras palabras, y cuando existan varias posibilidades para esa combinación (como con el ejemplo de ‘La’,’gente’), escogeremos aleatoriamente entre ellas. Imaginemos que escogemos ‘opina’, entonces escribimos ‘opina’ por la pantalla y buscamos en ‘gente’, ‘opina’ y así sucesivamente, hasta llegar a no_pala- bra. Para entender mejor el funcionamiento del programa recomendamos copiar el código fuente y pasarle unos ejemplos (pongamos, con cat texto.txt | ./markov.py) y ver los resultados. En el Listado 4 vemos un ejemplo de la salida utilizando el texto de este artículo. El texto generado casi tiene sentido, pero no del todo. Después podemos intentar cambiar cosas en el programa, por ejemplo, en lugar de utilizar 2 palabras como índice del diccionario, podemos probar con 1 o con 3, y también con el tamaño del texto que se le pase. Se pueden conseguir cosas muy interesantes. ■ INTRODUCCIÓNPrimeros Pasos 9PYTHONWWW.LINUX- MAGAZINE.ES [1] Python: http://www.python.org Recursos 01 #!/usr/local/bin/python 02 03 #Importamos dos módulos 04 #random [que hace] 05 #y sys [que hace] 06 import random 07 import sys 08 09 no_palabra = “n” 10 w1 = no_palabra 11 w2 = no_palabra 12 13 # GENERAMOS EL DICCIONARIO 14 dict = {} 15 16 for linea in sys.stdin: 17 for palabra in linea.split(): 18 dict.setdefault( (w1, w2), [] ).append(palabra) 19 w1 = w2 20 w2 = palabra 21 22 # Fin de archivo 23 dict.setdefault((w1, w2), [] ).append(no_palabra) 24 25 # GENERAMOS LA SALIDA 26 w1 = no_palabra 27 w2 = no_palabra 28 29 # puedes modificarlo 30 max_palabras = 10000 31 32 for i in xrange(max_palabras): 33 nueva_palabra = random.choice(dict[(w1, w2)]) 34 35 if nueva_palabra == no_palabra: 36 sys.exit() 37 38 print nueva_palabra; 39 40 w1 = w2 41 w2 = nueva_palabra Listado 4: markov.py Genera un Texto No-Tan-Aleatorio Para empezar, debemos saber por qué Python es obligatorio hacerlo de una manera. Como es un lenguaje tipo script, debemos poner ‘#!’ seguido de la ejecución del programa. También tenemos a nuestra disposición los operadores habituales de otros lenguajes: +, -, *, /, etc. Y una vez que sabemos cómo manejar operadores y asignaciones, se pueden mezclar: diccionarios de listas de diccionarios, diccionarios de listas, listas de Python también vienen provistas de muchas más opciones que sus semejantes en otros lenguajes. Por ejemplo, vamos a definir una lista que guarde una serie de espacios (logrados pulsando la tecla TABULADOR) y una sentencia. Esos espacios son vitales, ya que marcan la existencia de un texto que, aunque carece de sentido, normalmente se corresponde con la que Python trata las listas de diccionarios, diccionarios de listas, listas de Python resultan tan potentes, es que nos permiten referenciar a un elemento en la sangría de la OOP. - Es potente. Realizar un programa de 1000 lineas en Java, en Python es obligatorio hacerlo de una manera. Como es un diccionario con dos palabras como índice y las palabras que les siguen en el que muchas entradas referenciarán a una lista de más de un bloque de código Python. Ese bloque aparecerá en bucles, funciones o métodos. Si nos fijamos bien en la sangría de la memoria a bajo nivel como C con el tamaño del texto que se usa en el Listado 1. Listado 5: Salida de markov.py
  • 10. INTRODUCCIÓN Ficheros 10 PYTHON WWW.LINUX- MAGAZINE.ES En nuestro primer artículo vimos algo sobre cómo trabajar con objetos en Python. Fue muy simple, pero ya nos daba la posibilidad de organizar nuestro código en torno a ellos. Python hace un uso extensivo de los objetos en sus APIs, y especialmente del control de errores mediante excepciones, lo que nos da la opción de lanzarlas cuando algo va mal. Una excepción es un mensaje que pode- mos capturar cuando se ejecuta cierta función o método y aparece un error de algún tipo. Normalmente controlamos estos errores mediante el valor devuelto por la función (como por ejemplo en C). Esta técnica es engorrosa, pero al igual que todo, tiene sus virtudes y sus des- ventajas. Pero Python hace uso de las excepciones en su lugar. Cuando una función genera una excepción, decimos que eleva una excep- ción. Es muy normal tener que controlar las excepciones en las operaciones que realicemos con recursos que pueden no estar disponibles. Por eso las vamos a ver, puesto que aquí vamos a trabajar con archivos y conexiones a Internet. Crearemos un objeto que gestione un recurso que puede no estar disponible. En este caso el objeto gestiona una varia- ble (véase el Listado 1). Alguien puede crear un objeto de la clase obj_variable y llamar al método set_variable(23), pero ¿cómo puede estar seguro de que la variable var tiene el valor 23 después de la llamada? Puede que var no tuviese el valor inicial de 0, porque otra llamada anterior ya podría haberla asignado. Lo único que podría- mos hacer es llamar a reset_variable() y así asegurarnos de que nuestro valor sea asignado, pero entonces destruiríamos el valor anterior y no sabríamos qué podría pasar. Por lo tanto, necesitamos un meca- nismo de comunicación para darle a conocer al usuario que esa variable ya está asignada. Esto lo podemos hacer con las excepciones. En el Listado 2 aparece una clase que hereda de la clase Exception llamada Var_Asignada. Cuando en la clase obj_variable intentamos asignar un valor a la variable var y ésta no es 0, entonces se dispara, se eleva, la excepción Var_Asignada. Si no controlamos la por- ción de código en la que se encuentra set_variable() y aparece una excepción, el programa se detendrá y acabará. La idea detrás de las excepciones es que es posible tratarlas y evitar males mayores, pudiendo en ocasiones incluso recuperarnos de ellas. Para ello está la estructura try—except, con la cual rodea- mos el código que puede disparar excep- ciones (Véase el Listado 3). A partir de ahora, y hasta que no expli- quemos con más profundidad el tema de las excepciones, cuando digamos que una función genera una excepción, signi- ficará que ese código deberá estar rode- ado con una estructura try—except. Trabajo con Ficheros Ya que hemos conseguido cierta soltura con los conceptos de objetos en Python, ahora vamos a ver cómo se manejan los accesos a ficheros en él. Para acceder a un fichero, primero necesitamos crear un objeto file. El objeto file es parte de la librería base de Python, así que no es necesario importar ninguna librería. >>> archivo = file(‘texto.txt’) Por definición, file abre los ficheros en modo de sólo lectura. Eso significa que si el fichero no existe, obtendremos un error. Para verificar si el fichero existe podemos usar la función exists() de la librería os.path. >>> import os.path >>> os.path.exists(‘texto.txt’) True >>> os.path.extsts(‘algo- peludo-y-feo.txt’) False Por lo tanto, si vamos a abrir un fichero, podemos asegurarnos de que ya existe. Si en lugar de leerlo lo que queremos es crearlo, deberemos invocar al cons- tructor de file con los parámetros: >>> archivo = file(‘texto.txt’,U ‘w’) Este segundo parámetro opcional nos permite definir el tipo de acceso que vamos a realizar al fichero. Tenemos varias posibilidades: podemos leer (r), escribir (w), añadir al final del fichero (a) y también tenemos el acceso de lec- tura/escritura (r+w). Disponemos tam- bién del modificador b para indicar acceso binario. Por defecto, Python con- Siguiendo con nuestro paseo por Python, vemos características básicas, y concretamente en este artículo, el tratamiento de ficheros. Por José Mari Ruíz RuslanOlinchuk-123RF.com Manejo básico de ficheros Álbum Fotográfico
  • 11. sidera todos los ficheros de texto. Vemos todas las combinaciones en el Listado 4. Si todo ha ido bien, con cualquiera de estas llamadas tendríamos en archivo un objeto que gestiona el archivo indicado. Ahora podemos operar sobre él. Las operaciones más típicas son las de leer desde el archivo y escribir en él. Para ello, el objeto file dispone de los métodos read(), readline(), write() y writeline(). Todos ellos operan con cadenas de carac- teres: readline() y writeline() trabajan con líneas de texto (acabadas en retorno de carro), mientras que read() y write() lo hacen con cadenas sin restricciones. Lo que vemos en el Listado 5 son algunas manipulaciones sobre un fichero. Lo primero que tenemos que hacer es crear el fichero, para lo cual lo abrimos en modo de escritura, w, que lo creará o truncará el existente (lo borrará para crearlo de nuevo. Si lo hubiéramos querido añadir al final, habríamos usado a). Posteriormente escribimos en él una cadena con un retorno de carro en mitad (para hacer nuestras pruebas) y cerra- mos el fichero. Es importante cerrar los ficheros cuando dejemos de usarlos, pero en este caso la razón para cerrarlo es que vamos a volver a abrirlo en modo de lectura. Ahora volvemos a abrir el fichero en modo de lectura, y leemos 4 bytes que almacenamos en la variable cadena. Cuando leemos con read(), avanzamos en el fichero, siendo esta la razón de que readline() que viene a continuación lea la cadena “ mundon” en lugar de “Hola mundo”. También vemos que se para en el retorno de carro en lugar de continuar. El segundo readline() ya nos permite leer la cadena “Adiós mundo”. Pero… ¿qué ocurriría si en una de las lecturas nos encontrásemos con el fin de fichero? En el caso de que leyésemos una cadena con el fin de fichero (EOF), al final simplemente nos quedaríamos con la cadena hasta el EOF. En cambio, si sólo leemos el EOF, entonces obtenemos una null. Esto es importante para com- probar que hemos acabado con el fichero. Así, un bucle que escriba por pantalla el contenido del fichero compro- baría en cada vuelta si la cadena que devuelve readline() es null. Ahora que ya sabemos crear archivos, tenemos que aprender a borrarlos. Esto se realiza mediante la función remove() de la librería os. Esta función acepta la ruta de un fichero y lo borra. Si en lugar de un fichero le pasamos un directorio elevará una excepción OSError. >>> import os >>> os.remove (texto.txt) >>> Directorios y Sistema de Ficheros Con estos pocos métodos tenemos ya a nuestro alcance la manipulación básica de ficheros. Pero vamos a necesitar para nuestro programa la posibilidad de crear directorios. ¿Cómo lo haremos? Pues mediante la función mkdir(), que acepta una cadena y crea un directorio con ese nombre. Si queremos crear un directorio que esté dentro de otros directorios tam- bién nuevos tenemos que usar make- dirs(). Ambas funciones pertenecen al módulo os, por lo que para usarlas ten- dremos que hacer: >>> import os >>> os.mkdir(‘uno’) >>> os.makedirs(‘dos/tres’) Para borrar esos directorios usaremos las funciones rmdir() y removedirs(). La pri- mera borra un directorio, mientras que la segunda borra una ruta de directorios. Vamos a ver esto con más detenimiento. >>> os.rmdir(‘uno’) >>> os.removedirs(‘dos/tres’) rmdir() borrará el directorio “uno”, que no contiene ningún otro objeto en su interior (ni directorios, ni ficheros). En caso de tenerlo, la llamada devolvería un error. La función removedirs() comenza- ría a borrar desde el directorio que está más a la derecha de la ruta (“tres”) hacia el que está más a la izquierda (“dos”). Pero imaginemos que dentro de “dos” también hay un directorio “cuatro”. Entonces se borraría el directorio “tres”, y cuando la función fuese a borrar el directorio “dos”, se encontraría con que no puede porque existe dentro de él un directorio llamado “cuatro” y pararía. Imaginemos ahora que necesitamos cambiar el directorio en el que estamos trabajando. En el momento de arrancar el programa, el llamado “directorio de trabajo” – es decir, el directorio donde de manera predeterminada se realizarán todos los cambios – es el directorio que alberga el programa o bien el directorio desde el que se ejecutó. Pero, claro, no siempre querremos que el programa uti- lice ese directorio. Hay que tener en cuenta que, a no ser que utilicemos rutas absolutas, cualquier referencia a un fichero se tomará con relación al directorio de trabajo inicial. Para poder cambiar el directorio de tra- bajo, el módulo os tiene la función chdir(). Si lo invocamos dentro de nues- tro programa: >>> os.chdir(‘/tmp’) Desde ese momento, cualquier referencia a un fichero será direccionada a “/tmp”. Ahora podemos: • abrir, cerrar, modificar ficheros • crear, eliminar un directorio • cambiar el directorio de trabajo Vamos a ir un poco más allá. Llamadas a Otros Programas A veces es más sencillo usar una utilidad del sistema operativo que crearla noso- INTRODUCCIÓNFicheros 11PYTHONWWW.LINUX- MAGAZINE.ES W W W. L I N U X - M A G A Z I N E . E S 01 class obj_variable: 02 __init__(this): 03 var = 0 04 05 set_variable(this, valor): 06 if (var == 0): 07 var = valor 08 09 reset_variable(this): 10 var = 0 Listado 1: Una Clase Python 01 class Var_Asignada(Exception): 02 “”“ Excepción que se dispara al intentar asignar una variable ya asignada en obj_variable”“” 03 pass 04 05 class obj_variable: 06 “”“ Administra una variable “”“ 07 def __init__(self): 08 self.var = 0 09 10 def set_variable(self, valor): 11 if (self.var == 0): 12 self.var = valor 13 else: 14 raise Var_Asignada 15 def reset_variable(self): 16 self.var = 0 17 18 a = obj_variable() 19 a.set_variable(12) 20 a.set_variable(34) Listado 2: Uso de Excepciones
  • 12. INTRODUCCIÓN Ficheros 12 PYTHON WWW.LINUX- MAGAZINE.ES En este apartado vamos a comenzar con lo básico. Queremos traer un recurso de la red a nuestra máquina, y para ello emplearemos una URL del estilo http:// www.algunaweb.algo/imagen.jpg. Pero primero necesitamos crear una conexión con el servidor. Para ello vamos a utilizar la librería httplib que viene de serie con Python. Esta librería nos permite establecer una conexión con un servidor http y man- darle comandos. Los comandos http son simples, y de todos ellos sólo nos interesa uno, el comando GET. Cuando accedemos a un servidor http, por ejemplo para ver una página web, lo que hacemos es pedirle objetos. Esto se hace mediante el comando GET <objeto>. Por ejemplo, si queremos la página index.html de la web http:// www.python.org, primero conectamos con el servidor http y después, una vez conectados, le enviamos el comando GET index.html. En ese momento el servidor nos devuelve por el mismo canal el contenido del archivo index.html. Dicho así parece muy fácil, pero es una tarea que en un lenguaje de más bajo nivel requeriría gran cantidad de librerías y control de errores. Lo primero es importar la librería httplib. Creamos entonces una conexión con el host en cuestión y pedimos el archivo index.html. Esa conexión genera una respuesta. La respuesta está for- mada por varias partes, entre ellas un código numérico (como el famoso 404), un texto que describe el error y una conexión al archivo que pedimos. En el caso de una conexión correcta recibire- mos un 200, un OK y una conexión con el fichero. De esa conexión lee- mos con read() el contenido y lo almacenamos en una varia- ble que llamamos dato. Enton- ces podremos cerrar la cone- xión como si de un fichero se tratara. En ese momento ya tenemos la información que queríamos en dato y el canal cerrado. No es muy difícil, ¿no? Veremos un ejemplo en el programa final de este artículo. Paso de Parámetros Estamos acostumbrados a poder pasar parámetros a los programas. En UNIX es algo común. Pero… ¿cómo podemos obtener los pará- metros de ejecución en Python? De nuevo tenemos que recurrir a una libre- ría: la librería sys. sys nos proporciona el acceso a los argumentos a través de su variable argv. Esta variable es en realidad una lista, por lo que podemos obtener los argumentos accediendo a las posiciones de la misma. La posición 0 contiene el nombre del programa que estamos ejecutando y, a partir de la posición 1, encontraremos los parámetros pasados. Al ser una lista, podemos conocer la cantidad de paráme- tros llamando a len(). Programa Ahora es el momento de poner todo lo aprendido en práctica con un programa que puede ser útil. En este caso vamos a crear uno que realizará las siguientes tareas: • El programa aceptará un parámetro de entrada que le indicará el nombre de un fichero. • El programa abrirá ese fichero y lo leerá línea por línea. Cada línea del fichero será la dirección URL de una imagen. • Cada URL será introducida dentro de una lista para su uso posterior. tros, como por ejemplo, un procesado usando tuberías en UNIX. Puede que simplemente tenga que acceder a alguna información como la que nos da uname. El caso es que siempre es importante tener la posibilidad de ejecutar otros pro- gramas desde nuestro programa Python. Para ello usamos la función system del módulo os. Por ejemplo: >>> import os >>> os.system (‘uname -a’) Linux rachel 3.1.2-1.fc16.x86_64 #1 SMP Tue Nov 22 09:00:57 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux 0 >>> El parámetro que le pasamos a system es una cadena con la instrucción Bash (en este caso) y sus switches y flags. system nos devuelve la salida de la instrucción ( Linux rachel 3.1.2-1.fc16.x86_64 #1 SMP Tue Nov 22 09:00:57 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux) y el estado de salida resultante de la ejecución de la ins- trucción (0 – recuérdese que 0 indica que la instrucción ha acabado sin errores). Python y la Web Python posee gran cantidad de librerías para trabajar con recursos de Internet. De hecho, Django [1] , un servidor de aplicaciones con gran éxito, está creado en Python y hace uso de todas sus carac- terísticas. Mailman [2] o Bittorrent [3] son también buenos ejemplos. Debido a su flexibilidad, Python es usado como lenguaje de implementación para multitud de aplicaciones de red así como aplicaciones distribuidas. Por eso, no es de extrañar que Python suela ser el lenguaje en el que se implementan muchas de las más novedosas tecnolo- gías de red. 01 >>> try: 02 ... set_variable(12) 03 ... set_variable(34) 04 ... except: 05 ... print “ERROR: Se ha intentado asignar” 06 ... print “un valor a una variable ya asignada” 07 ... 08 ERROR: Se ha intentado asignar 09 un valor a una variable ya asignada 10 >>> Listado 3: Más Excepciones 01 >>> archivo = file(‘/tmp/texto.txt’,’w’) 02 >>> archivo.write(“Hola mundonAdios mundo”) 03 >>> archivo.close() 04 >>> 05 >>> archivo = file(‘/tmp/texto.txt’,’r’) 06 >>> cadena = archivo.read(4) 07 >>> cadena 08 ‘Hola’ 09 >>> cadena = archivo.readline() 10 >>> cadena 11 ‘ mundon’ 12 >>> cadena = archivo.readline() 13 >>> print cadena 14 ‘Adios mundo’ 15 >>> archivo.close() Listado 5: Lectura y Escritura de Ficheros 01 archivo = file(‘texto.txt’,’r’) 02 archivo = file(‘texto.txt’,’w’) 03 archivo = file(‘texto.txt’,’a’) 04 archivo = file(‘texto.txt’,’r+w’) 05 archivo = file(‘texto.txt’,’r+b’) 06 archivo = file(‘texto.txt’,’rb’) Listado 4: Acceso a Ficheros
  • 13. INTRODUCCIÓNFicheros 13PYTHONWWW.LINUX- MAGAZINE.ES 001 #!/usr/bin/python 002 003 # ---NOTA-------------------------------------- 004 # El fichero que debe ser pasado como argumento 005 # debe consistir en un listado con una url por 006 # línea. 007 # --------------------------------------------- 008 009 class Lista_URLs: 010 “”“Recibe un fichero y carga sus cadenas en una lista. Provee de métodos para obtener de nuevo las cadenas desde la lista.”“” 011 012 def __init__(self,nombre): 013 # La lista donde guardaremos las URLs 014 self.lista= [] 015 # El contador que usaremos para comprobaciones 016 self.contador = 0 017 018 # pasamos el nombre del fichero menos el último carácter 019 self.archivo = file(nombre) 020 self.cadena = self.archivo.readline() 021 022 while(self.cadena != ‘n’): 023 #Metemos la cadena en la lista 024 self.lista.append(self.cadena) 025 self.cadena = self.archivo.readline() 026 self.archivo.close() 027 028 029 def rebobina(self): 030 # Hace que se comience de nuevo 031 # por el principio en la lista. 032 self.contador = 0 033 034 035 def siguiente(self): 036 # Devuelve el siguiente elemento o 037 # ‘’ en caso de llegar al final. 038 if ( self.contador >= len(self.lista)): 039 return ‘’ 040 else: 041 self.valor = self.lista[self.contador] 042 self.contador = self.contador + 1 043 return self.valor 044 045 def fin(self): 046 # Comprueba que hemos llegado al final 047 # de la lista. Preguntamos si hemos llegado 048 # al final antes de avanzar. 049 return (self.contador == len(self.lista)) 050 051 def crea_directorio(cadena): 052 # Comprueba si el directorio especificado por 053 # cadena existe, en caso contrario lo crea 054 # y cambia el directorio de trabajo 055 # al directorio creado. 056 057 componentes = cadena.split(‘.’) 058 059 if(os.path.exists(componentes[0])): 060 print “Error: el directorio ya existe” 061 sys.exit() 062 else: 063 # Creamos el directorio 064 os.makedirs(componentes[0]) 065 os.chdir(componentes[0]) 066 print ‘Creando directorio ‘ + componentes[0] 067 068 def descarga_urls(lista): 069 # Recorre la lista de urls usando el objeto 070 # Lista_URLs, las descarga y después las 071 # guarda en ficheros con el mismo nombre que 072 # el de la imagen. 073 074 lista.rebobina() 075 076 while( not lista.fin() ): 077 url = lista.siguiente() 078 079 # dividimos la url en dos partes 080 # lo que descargamos y la url http 081 082 # Componentes es una lista que contiene 083 # las cadenas resultantes de trocear la 084 # cadena de texto de la URL usando ‘/’ 085 # como separador. Por ejemplo: 086 # http://www.python.org/index.html 087 # componentes = [‘http:’, ‘’, ‘www.python.org’, 088 # ‘index.html’] 089 componentes = url.split(‘/’) 090 servidor = componentes[2] 091 092 # Construimos la ruta de la imagen, que 093 # consiste en toda la ruta si eliminamos 094 # al servidor y a http:// 095 ruta_imagen = ‘/’ 096 for i in range( 3, len(componentes)): 097 ruta_imagen = ruta_imagen + ‘/’ + componentes[i] 098 099 # Descarga el fichero y lo guarda con el nombre. 100 # El nombre se saca de la URL. 101 # url[:-1] es la cadena url menos el último carácter. 102 print ‘Descargando imagen: ‘ + url[:-1] 103 conexion = httplib.HTTPConnection(servidor) 104 conexion.request(“GET”, ruta_imagen) 105 respuesta = conexion.getresponse() 106 # datos contiene ahora la imagen y la guardamos 107 datos = respuesta.read() 108 conexion.close() 109 110 # el nombre del fichero es el último elemento 111 # de la lista componentes 112 nomb_fichero = componentes[len(componentes) -1] 113 # eliminamos el n final 114 nomb_fichero = nomb_fichero[:-1] 115 116 # Abrimos el fichero, escribimos y cerramos 117 archivo = file(nomb_fichero ,’w’) 118 archivo.write(datos) 119 archivo.close() 120 121 def genera_index(lista): 122 123 # Crea un fichero index.html. 124 # Genera la cabecera, recorre la lista de URLS 125 # y por último escribe el pie. 126 # Es posible mejorarlo introduciendo separadores 127 # o títulos entre las imágenes ;) 128 Listado 6: Agarrafotos.py
  • 14. • Leer las URLs. • Crear Directorio y cambiar el directo- rio de trabajo. • Descargar las URLs. • Generar el archivo HTML. Seguiremos estos puntos para crear las funciones. Las URLs las almacenaremos en una lista. ¿Deberíamos usar objetos? Esta es una de las cosas maravillosas que ofrece Python: NO estamos obligados a usar objetos. Y no digo que los objetos sean malos, sino que en ocasiones pue- den llegar a ser engorrosos. Por ejemplo, podríamos crear un objeto Lista_URLs que aceptase como parámetro en su constructor el nombre de un fichero y que después nos permitiese ir cogiendo las URLs una detrás de otra. También podemos hacer lo mismo usando una función que cargue las URLs en una variable global. Aquí vamos a hacerlo con un objeto. Es en este momento cuando se deja al lector que explore la posibilidad de sustituir el objeto por una variable global y las funciones de lista. Este programa es muy simple, pero de nuevo retamos a los lectores a mejorarlo y a introducirle, por ejemplo, control de excepciones. Suerte. ■ • Una vez que hayamos acabado de leer el fichero, lo cerraremos y entraremos en la segunda parte del programa. • Crearemos un directorio con el nom- bre del archivo que nos hayan dado. • Cambiaremos el directorio de trabajo a ese directorio. • Descargaremos cada una de las URLs dentro del directorio. • Generaremos un archivo index.html que muestre las imágenes. ¿Mucho trabajo? Para eso están los pro- gramas. Evidentemente no realizaremos todas las comprobaciones que serían necesarias, ya que en tal caso el pro- grama se alargaría demasiado, por lo que se deja al lector la opción de incluir mejoras. Pensemos ahora en su diseño. Tenemos varias partes: • Comprobar y almacenar la opción con el nombre del archivo. INTRODUCCIÓN Ficheros 14 PYTHON WWW.LINUX- MAGAZINE.ES [1] La infraestructura Django para aplica- ciones web: https://www.djangoproject.com/ [2] El programa administrador de listas de correo Mailman: http://www.gnu. org/software/mailman/ [3] El programar para administración de Torrente BitTorrent: http://bittorrent.com/ Recursos 129 print ‘Generando índice index.html’ 130 131 archivo = file(‘index.html’,’w’) 132 133 # Cabecera 134 archivo.write(‘<html>n’) 135 archivo.write(‘<head>n’) 136 archivo.write(‘<title> Imagenes </title>n’) 137 archivo.write(‘</head>n’) 138 archivo.write(‘<body>n’) 139 archivo.write(‘<h1>Imagenes</h1>n’) 140 archivo.write(‘<ul>n’) 141 142 # siempre antes de recorrer: 143 lista.rebobina() 144 url = lista.siguiente() 145 146 # Dividimos la URL para poder utilizar 147 # partes de ella. 148 componentes = url.split(‘/’) 149 imagen = componentes[len(componentes) - 1] 150 151 # Recorremos las urls 152 while( url != ‘’): 153 # Imagen en HTML 154 archivo.write(‘<li><img src=”‘+ imagen +’”></img></li>n’) 155 url = lista.siguiente() 156 componentes = url.split(‘/’) 157 imagen = componentes[len(componentes) - 1] 158 159 # ... y por último el pie. 160 161 archivo.write(‘</ul>n’) 162 archivo.write(‘</body>n’) 163 archivo.write(‘</html>n’) 164 165 archivo.close() 166 167 #------------------------------------------------ 168 # Main 169 #------------------------------------------------ 170 171 # Esta es la técnica estándar para organizar el 172 # código en Python, se usa la siguiente construcción 173 # como punto de arranque. 174 175 if __name__ == ‘__main__’: 176 177 import httplib 178 import os 179 import os.path 180 import sys 181 182 # Comprobamos los argumentos... 183 184 if len(sys.argv) == 2: 185 #Pasamos el fichero al constructor 186 lista = Lista_URLs(sys.argv[1]) 187 188 189 crea_directorio(sys.argv[1]) 190 191 descarga_urls(lista) 192 193 genera_index(lista) 194 195 elif len(sys.argv) == 0: 196 # Vaya, han ejecutado sin poner argumentos... 197 # les recordaremos como va esto ;) 198 print ‘La sintaxis del programa es:n’ 199 print sys.argv[0] + ‘ archivon’ 200 print ‘El archivo debe contener una URL por línea’ 201 202 else: 203 # Alguien se ha quedado corto y se ha pasado 204 # con el número de argumentos. 205 print “ERROR: la sintaxis es “ + sys.argv[0] + “ <fichero>” Listado 6: Agarrafotos.py (Cont.)
  • 15. Equivocarse es humano, y a pesar de todo el mito que rodea a los programado- res, hasta el mejor de ellos comete erro- res diariamente. En muchas ocasiones es mucho más complicado eliminar un BUG que crear el propio programa. Cuenta le leyenda que el nombre de BUG viene de la misma palabra que en inglés significa bicho. Dicen que los primeros ordenado- res eran grandes máquinas que genera- ban gran cantidad de calor, por lo que innumerables insectos y otras alimañas se introducían en ellos. De vez en cuando, alguno tocaba dos cables y que- daba frito, provocando un fallo en el sis- tema. Actualmente se conoce como BUG a todo error o situación no controlada que impida a un programa realizar tu tarea con normalidad. Lo cierto es que estamos bastante acostumbrados a que los BUGS sean parte de nuestra vida. Ventanas que no se cierran, programas que consumen todo el espacio en memo- ria o videojuegos que se quedan blo- queados. Python es un lenguaje dinámico, como muchos otros. La principal ventaja es que nos permite programar a alto nivel, desentendiéndonos de toda la gestión de recursos a bajo nivel que hace tan pesada la programación en otros lengua- jes como por ejemplo C. Pero no todo el monte es orégano. También hay una parte negativa: Python no es un lenguaje demasiado estricto. Podemos hacer lo que queramos con las variables sin que el intérprete se queje hasta el último momento. Esta característica impide la posibilidad de verificar automáticamente todo el código en el momento en que es compilado. Un código totalmente erró- neo, en el que por ejemplo se suman letras y números, puede pasar desaperci- bido en nuestro programa hasta el día que se ejecuta y genera un error que dejará al usuario con la boca abierta, y ciertas dudas sobre nuestra valía como programadores. Casi a la vez que surgieron los lengua- jes de programación aparecieron unos programas que han ido unidos a ellos: los debuggers. Exiten muchos debuggers diferentes. GNU desarrolló DDD, pero hace tiempo que no se ve actividad en este proyecto (ver Recurso [1]). Valgrind ha conseguido mucha fama en proyectos que emplean C++ ( ver Recurso [2]). En este artículo vamos a echar un vis- tazo a las herramientas que podemos usar para localizar los fallos en nuestros programas Python, y en particular a la que viene de serie con Python: el PDB, Python DeBugger (podemos ver la docu- mentación de PDB en el Recurso [3]). Un Bug, Dos Bugs, Tres Bugs… Los lenguajes dinámicos, como decía- mos antes, tienen sus propias virtudes y desventajas. Los programadores más duros suelen decir que programar con lenguajes dinámicos es como jugar con juguetes: no hay bordes cortantes con los que cortarse ni partes pequeñas con las que atragantarnos. Vamos, que son poco menos que una versión infantil de los lenguajes “serios”. Lo cierto es que hay mucha gente que no entra en estos debates. Yo, por lo menos, prefiero hacer un programa tan rápido como sea posi- ble y espero que funcione casi a la pri- mera. ¿De dónde salen los BUGS? Lo más probable es que haya siempre una varia- ble implicada. La explicación es simple: las variables son la única parte del pro- grama que realmente no controlamos. Mientras el resto del código hace exacta- mente lo que le indicamos que haga, por ejemplo abrir un fichero, en las variables suceden todo tipo de cosas mientras el INTRODUCCIÓNDebugging 15PYTHONWWW.LINUX- MAGAZINE.ES Da igual lo buenos programadores que seamos, tarde o temprano daremos con ese BUG que será nuestro peor enemigo. Veamos cómo podemos emplear herramientas para derrotarlo con mayor facilidad. Por José María Ruíz Eliminación de bugs de programas Python Desparasitando Serpientes SebastianKaulitzki-123RF.com
  • 16. INTRODUCCIÓN Debugging 16 PYTHON WWW.LINUX- MAGAZINE.ES programa está en ejecución. El problema es que no vemos esas variables mientras el programa está funcionando, así que tenemos que imaginarnos qué está pasando. En condiciones ideales se puede per- der el tiempo tratando de localizar los fallos a ojo de buen cubero, pero bajo estrés y con plazos, toda ayuda es poca. Python además nos permite almacenar cualquier valor dentro de una variable. Las variables en los lenguajes dinámicos como Python son casi mágicas. En ellas podemos almacenar un número: >>> mivariable = 32 Y punto seguido almacenar un objeto: >>> class Persona: ... def __init__(this,nombre): ... this.nombre = nombre ... >>> mivariable = PersonaU (‘Carlos’) Y sigue siendo la misma mivariable, pero de alguna manera su naturaleza ha cam- biado. Ahora imagina que esta situación ocurre en un programa que has creado. Mientras tecleas piensas, “‘mivariable’ contiene una distancia” y operas con ella, sólo que, sin que te des cuenta, en reali- dad mivariable contiene un objeto de la clase Persona ¿qué pasara si intentas sumarle 18? >>> a + 18 Traceback (most recent call last): File “<stdin>”, line 1, in ? TypeError: unsupported operand type(s) for +: ‘instance’ and ’int’ >>> ¡ERROR! El intérprete de Python nos advierte de que algo no marcha bien: hay un error de tipo, no es posible sumar un número entero y una instancia de un objeto tal como hemos definido la clase. Desagradable ¿verdad? Por lo menos este tipo de BUG, que es tan fácil de encontrar que el propio intérprete de Python lo encuentra. ¿Qué ocurría si el programa no fallase, sino que no nos diese el resultado esperado? ¿Y si el pro- grama le dijese a un cliente que su edad actual es -323134.32 años? Este es sin duda el peor tipo de BUG existente: el semántico. El intérprete de Python es perfecto localizando errores sintácticos, aquéllos que tienen que ver con las propias pala- bas que escribimos. Si hacemos referen- cia a una variable que no está definida, Python trata de buscar su valor, ve que no existe la variable y se queja. Los errores semánticos son harina de otro costal, porque se refieren a fallos que aparecen debido a que no se entiende lo que está pasando. Un ejemplo simple es el que hemos visto antes, cuando hemos tratado de sumar una variable con una instancia de un objeto que no responde a la suma con un número. Solucionar un BUG semántico puede llevar desde segundos a años. De hecho, existe mucho software, tanto comercial como libre, con BUGS que no han sido resueltos en años. Ahora que el pro- blema ha sido planteado con más deteni- miento, conviene ver con qué arsenal contamos en nuestra batalla contra los BUGS. Depurando Código Digamos que estamos haciendo un script para mostrar, usando como caracteres las vacaciones que han escogido una serie de empleados de una empresa. Como no queremos que el código sea largo ni demasiado complicado, lo hemos redu- cido al mínimo. La función tomará una lista de tuplas, que representa las vaca- ciones de una persona en un mes. Cada tupla representa un periodo de vacacio- nes, con una fecha de inicio y una fecha de fin. La idea es muy simple, aceptamos esa lista y después devolvemos una cadena donde los días de trabajo se representan por un espacio, y los de vacaciones con un “#”. No es muy com- plicado ¿verdad? Así que nos ponemos manos a la obra, es algo sencillo, no nos llevará ni 10 minutos, acabamos escribiendo el código del Listado 1. Pero nos interrum- pen antes de probar la función, y cuando volvemos al ordenador y ejecu- tamos un programa de prueba ¡se queda bloqueado! ¡No puede ser!, en tan pocas líneas de código no puede haber un error tan grave. Después de unos minu- tos de frustración, abandonamos la ins- pección visual y pasamos a trabajar PDB. PDB es el Python DeBugger y viene de serie con Python. Eso está muy bien, porque en caso de necesitarlo siempre lo tendremos a mano. A diferencia de otros debuggers, PDB se puede usar como si fuese una librería. Podemos integrarla en nuestros programas y eliminarla cuando ya los hayamos arreglado. Como es posi- ble observar en el Listado 1, hemos importado PDB y hemos pasado como parámetro a pdb.run() una cadena en la que invocamos la función vacaciones() con un argumento acorde. Si ejecutamos el programa, veremos lo siguiente en nuestro terminal: josemaria@linuxmagazine$U ./p.py > <string>(1)?() (Pdb) Figura 1: ¿A quién dejaremos sin vacaciones? 01 #!/usr/local/bin/python 02 03 import pdb 04 05 def vacaciones (l): 06 cadena = “” 07 for i in range(1,31): 08 encontrado = False 09 max = len(l) 10 k=0 11 while(not(encontrado) or k<max): 12 rango = l[k] 13 inf,sup=rango 14 if ((i >= inf) and (i <= sup)): 15 encontrado = True 16 else: 17 k+=1 18 19 if (encontrado): 20 cadena += “#” 21 else: 22 cadena += “ “ 23 24 return cadena 25 26 pdb.run(‘vaca- ciones([(1,3),(6,10)])’) Listado 1: El Código Nefasto
  • 17. Muy bien, el PDB comienza a hacer su trabajo. En lugar de no hacer nada, como haría la función vacaciones() si el pro- grama se limitase a ejecutarla, entramos en lo que parece el prompt del shell de PDB. Esta shell tiene sus propios coman- dos, no tiene nada que ver con Python. Para ver los comandos disponibles pode- mos emplear el comando h: (Pdb) h Documented commands (type help <topic>): ================================ EOF break condition disable help list q step w a bt cont down ignore n quit tbreak whatis alias c continue enable j next r u where args cl d exit jump p return unalias 09 b clear debug h l pp s up Miscellaneous help topics: ========================== exec pdb Undocumented commands: ====================== retval rv (Pdb) ¡Buff! estos son demasiados comandos. Como suele ocurrir la primera vez que un principiante en Linux pulsa dos veces tabulador en BASH, lo que vemos nos asusta. En este caso no son tantos comandos (en un Linux estándar hay miles de ejecutables), pero sí más extra- ños. Debuggear es algo que SIEMPRE se hace bajo presión, por lo que todo el tiempo que ahorremos es oro. Así que los creadores de PDB nos ahorran segundos reduciendo los comandos a letras. Podemos ver lo que hace un comando usando de nuevo la letra h: (Pdb) h l l(ist) [first [,last]] List source code for the current file. Without arguments, list 11 lines around the current line or continue the previous listing. With one argument, list 11 lines starting at that line. With two arguments, list the given range; if the second argument is less than the first, it is a count. (Pdb) El comando l sirve para mostrar visual- mente en qué parte del código estamos en un momento dado; como nos pica la curiosidad ejecutamos l: (Pdb) l [EOF] Vaya, resulta que no hemos comenzado aún, por lo que no estamos en ninguna parte. El comando que probablemente usemos más a menudo es s ¿Por qué? pues porque es el comando que hace que PDB avance una línea y la ejecute: (Pdb) s --Call-- > /home/josemaria/p.py(5)U vacaciones() -> def vacaciones (l): Muy bien, comenzamos a ejecutar el trozo de código Python que pasamos a pdb.run(). Por el momento no pasa nada interesante, aunque estaría bien ver qué contiene la variable l, para ello podemos usar el comando p que hace las funciones de print: (Pdb) p l [(1, 3), (6, 10)] Efectivamente, l contiene el parámetro que hemos pasado a la función. Ya esta- mos en ruta, así que avancemos unos cuantos pasos más: (Pdb) s > /home/josemaria/p.py(6) vacaciones() -> cadena = “” (Pdb) s > /home/josemaria/p.py(7) vacaciones() -> for i in range(1,31): (Pdb) s > /home/josemaria/p.py(8) vacaciones() -> encontrado = False (Pdb) s > /home/josemaria/p.py(9) vacaciones() -> max = len(l) (Pdb) Hemos avanzado 4 pasos y puede que nos hallamos perdido. ¿Dónde estamos? ¿Qué estamos haciendo? ¿Hacia dónde vamos? El comando l resuelve todas nuestras dudas: (Pdb) l 4 5 def vacaciones (l): 6 cadena = “” 7 for i in range(1,31): 8 encontrado = False 9 -> max = len(l) 10 k=0 11 while(not(encontrado) or k<max): 12 rango = l[k] 13 inf,sup=rango 14 if ((i >= inf) and (i <= sup)): (Pdb) Ya me sitúo, acabamos de entrar en el bucle for, avancemos un poco más: (Pdb) s > /home/josemaria/p.py(10)U vacaciones() -> k=0 (Pdb) s > /home/josemaria/p.py(11)U vacaciones() -> while(not(encontrado) orU k<max): (Pdb) INTRODUCCIÓNDebugging 17PYTHONWWW.LINUX- MAGAZINE.ES Figura 2: IDLE no es bello, pero es práctico. Figura 3: El depurador de IDLE.
  • 18. variable encontrado sea True. Si todo va bien, el siguiente paso después de eva- luar las condiciones del while será salir del mismo y pasar a las siguiente instruc- ción fuera del while: (Pdb) s > /home/josemaria/p.py(12)U vacaciones() -> rango = l[k] (Pdb) ¿Pero qué ocurre aquí? Esto no debería pasar. La única explicación posible es que la condición del while esté… ¿es eso un or? ¡Debería ser un and! Deberíamos salir si hemos encontrado que el día per- tenece a un rango, o si no quedan rangos que comprobar. Ahí estaba nuestro BUG, tres simples letras, se cambian y pro- blema solucionado. Ahora que ya sabemos lo que pasa, sólo queda salir del debugger usando el comando q. Nuestro nuevo código ya está listo para ser usado (ver Figura 1). Y Ahora de Forma Fácil ¿No hay una manera más «moderna» de conseguir esto mismo? Pues sí, gracias a IDLE (ver Recurso [4]). IDLE es el entorno de desarrollo que viene, también, junto a Python. En la Figura 2 se puede observar el aspecto que tiene IDLE una vez que se ejecuta. No es ninguna belleza, pero es práctico, reemplaza al intérprete de comandos de Python y simplifica algunas tareas. En particular, estamos interesados en cómo puede simplificar el debugging. Para ello sólo tenemos que ir al menú Debug que aparece en la barra de menú de IDLE y activar Debugger. Aparecerá una ventana como la que puede obser- varse en la Figura 3. El lector no debe extrañarse demasiado con esta nueva ventana, viene a condensar en un solo lugar todo lo que hemos visto sobre PDB: hay un botón llamado STEP, que nos permitirá avanzar en el código paso a paso, y también hay un área llamada Locals, donde iremos viendo el valor de las variables que se vayan declarando en el código, de forma que podremos ir con- trolando la evolución del programa de un solo vistazo. Para ello sólo tenemos que cargar el programa en IDLE y veremos cómo se abre una especie de editor de textos como el de la Figura 4, en el que debere- mos seleccionar en el menú Run la opción Run Module. Con este paso carga- remos el fichero y comenzaremos a eje- cutarlo. Como antes seleccionamos la opción Debugger, IDLE se cargará en la ventana de debugging y podremos comenzar a visionar la evolución del programa conforme pulsemos sobre el botón Step. No es que IDLE sea un gran avance respecto al uso de PDB, pero desde luego simplifica el debugging. Conclusión Los debuggers no son una excusa para crear programas sin fijarnos demasiado en los problemas. Pero si no tenemos claro qué está ocurriendo o si ya no sabemos qué hacer, entonces un debug- ger como PDB puede ayudarnos a tener una imagen más clara de lo que pasa en nuestro programa. Existen bugs que no pueden cazarse con PDB, pero son tan extraordinariamente raros, que es posi- ble que jamás nos encontremos con uno. Los debuggers nos permiten progra- mar sin miedo a no entender lo que esta- mos haciendo, y es precisamente eso lo que nos permitirá avanzar y aprender más rápidamente. ¡Perdámosle el miedo a los BUGS! ■ Bueno, llegamos a una encrucijada. Cuando ejecutamos la función sin PDB, parece como si el programa nunca aca- base. Esto implica que hay algo que se repite eternamente. En este programa hay dos bucles, que son los únicos elementos que pueden repetirse eternamente. El pri- mero es un bucle for con un principio, 1, y un fin, 31, por lo que podemos descar- tarlo como culpable. El segundo sospe- choso es ese bucle while, que en un pri- mer momento no tiene porqué acabar, puede que jamás pare. Si un bucle while no para es porque las condiciones que lo controlan siempre se dan. En este código se supone que el if dentro del bucle while hace que éste pare alguna vez, así que algo debe fallar ahí dentro. Comencemos comprobando los valores de las variables que controlan el bucle: (Pdb) p encontrado False (Pdb) p k 0 (Pdb) p max 2 (Pdb) De acuerdo, todo parece en su sitio. Si avanzamos un poco: > /home/josemaria/p.py(12) vacaciones() -> rango = l[k] (Pdb) s > /home/josemaria/p.py(13) vacaciones() -> inf,sup=rango (Pdb) s > /home/josemaria/p.py(14) vacaciones() -> if ((i >= inf) and (i <= sup)): (Pdb) s > /home/josemaria/p.py(15) vacaciones() -> encontrado = True (Pdb) s > /home/josemaria/p.py(11) vacaciones() -> while(not(encontrado) or k<max): (Pdb) Resulta que hemos entrado en una tupla que representa unas vacaciones, el día representado por i pertenece a las vaca- ciones. Por tanto, hemos hecho que la INTRODUCCIÓN Debugging 18 PYTHON WWW.LINUX- MAGAZINE.ES [1] Documentación del depurador PDB: http://docs.python.org/lib/module- pdb.html [2] Valgrind captura errores que compro- meten la memoria en: http://valgrind.org/ [3] Data Display Debugger: http://www.gnu.org/software/ddd/ [4] El entorno de desarrollo IDLE: http://www.python.org/idle/ Recursos Figura 4: El seudo-editor de IDLE.
  • 19. Existe un gran misticismo en torno a los conceptos de función lambda y al concepto de cierre. Siempre que aparece un nuevo lenguaje de programación suele venir acompañado de una discu- sión que demuestra que el nuevo len- guaje es mejor porque incorpora alguno de estos dos conceptos. Quien esté un poco al tanto de los últimos «avances» habrá escuchado decir que C# incorpora las funciones lambda y que la próxima versión java al fin las tendrá entre su arsenal. Las funciones lambda reciben su nom- bre de la teoría del cálculo lambda de Alonzo Church [1], que junto a Alan Turing, sentaron las bases de la teoría de computación. Mientras Turing utilizó en su teoría una máquina abstracta e imagi- naria a la que se llamó Máquina de Turing, Alonzo utilizó un enfoque más tradicional, creando una serie de reglas que permitían realizar computaciones. Su sistema requería de un tipo de fun- ción especial, para la que usó la letra lambda. Las funciones lambda que vere- mos comparten sólo algunas de las características que Alonzo definió para las suyas, y podemos decir que lo que las define es que son anónimas: las funcio- nes lambda no tienen nombre. ¿Cómo es esto posible? ¿Para qué que- rríamos algo así? Son sólo dos preguntas que trataremos de resolver en este artí- culo mientras desmitificamos un con- cepto tan abstracto a primera vista. Las Funciones Lambda Las funciones lambda son el concepto más sencillo de los que vamos a ver en este artículo. Python las soporta desde hace un buen tiempo, y se encuentran integradas en la librería base de Python. También conocidas como funciones anó- nimas, no son más que funciones sin nombre que podemos crear en cualquier momento y pasar como argumento a otras funciones: >>> a = lambda x : x + 1 >>> a(2) 3 >>> Recordemos que en Python las variables no son más que nombres que asignamos a cosas y no contenedores de esas cosas. Esta diferencia es vital para comprender por qué podemos asignar una función a una variable y posteriormente asignar un valor a la misma (ver Figura 1). En este sencillo ejemplo hemos creado una función que suma el número 1 al número que pasemos como argumento. La definición de una función lambda siempre comienza con la palabra lambda seguida de los argumentos que vamos a aceptar. Detrás de los argumentos usa- mos el símbolo : para separar la defini- ción del cuerpo de la función. Las fun- ciones lambdas, al ser anónimas, deben almacenarse en una variable si quere- mos reutilizarlas, y se comportarán AVANZADOFunciones Lambda 19PYTHONWWW.LINUX- MAGAZINE.ES Funciones lambda en Python Sin Nombre Python es un lenguaje de programación multiparadigma, y las funciones lambda son parte fundamental de él, aunque como veremos, existen buenas razones para no abusar de ellas. Por José María Ruíz ©stylephotographs-123RF.com
  • 20. AVANZADO Funciones Lambda 20 PYTHON WWW.LINUX- MAGAZINE.ES como una función tradicional a la que podremos llamar pasándole parámetros entre dos paréntesis (). Existen varias restricciones en el uso de las funciones lambda. La primera es que siempre deben devolver un valor. Son funciones en el sentido estricto de las matemáticas, aceptan valores, los transforman y devuelven algún valor. En Python podemos devolver varios valores si lo deseamos: >>> b = lambda x: (x,x+1) >>> b(2) (2,3) >>> La segunda restricción es que sólo pue- den contener una expresión. Esta restric- ción limita bastante el poder de las fun- ciones lambda en Python. En Ruby, por ejemplo, las funciones lambda (también llamadas bloques) pueden contener tan- tas expresiones como deseemos. En Python se decidió añadir esta restricción para que los desarrolladores terminaran empleando las funciones lambda allí donde una función tradicional podría valerles (en Javascript es algo que se hace habitualmente). Cuando violemos una de estas restricciones, Python gene- rará una excepción: >>> c = lambda x: y = x+1 File “<stdin>”, line 1 c = lambda x: y = x+1 ^ IndentationError: unexpected U indent En este caso hemos tratado de realizar una asignación dentro de una función lambda. Lo que sí podemos hacer es pasar más de un parámetro a la fun- ción: >>> d = lambda x,y: x*y >>> d(2,3) 6 >>> Podemos, de forma limitada, emplear sentencias condicionales, puesto que Python nos permite usar la fórmula if...else como si fuese una expresión: >>> d = lambda x: ‘Yuju’ U if x > 2 else ‘ooooh’ >>> d(2) ‘ooooh’ >>> d(3) ‘Yuju’ Pero… ¿Para qué Sirven? Las limitaciones a las funciones lambda en Python tienen un objetivo bien defi- nido: evitar el mal uso que se puede hacer de ellas. Se restringe su uso a aquellas funciones donde es necesario pasar operaciones sencillas que el dise- ñador original de una función no puede predecir de antemano. Por ejemplo, si queremos ordenar una lista, la función de ordenación sorted() intentará compa- rar los elementos de la misma usando los métodos que existen por defecto. Pero ¿qué ocurre si los datos a ordenar son algo especiales? Imaginemos que tene- mos una lista de datos donde cada ele- mento es un tupla con el nombre y la edad de una serie de personas: >>> l = [(‘Luis’, 65), U (‘Juan’,28),U (‘Montse’, 33)] ¿Cómo podemos indicar a sorted que queremos ordenar la lista por edades? El diseñador de sorted no puede predecir todas las posibles estructuras de datos que se pasarán a la función. Existen tres opciones, u obligamos a la persona que pasa los datos a encapsularlos en objetos con un método que nos permita comparar dos objetos: 01 from functools import total_ordering 02 03 @total_ordering 04 class Edad(object): 05 def __init__(self, nombre,edad): 06 self.nombre = nombre 07 self.edad = edad 08 09 def __eq__(self, otro): 10 return cmp(self.edad, otro.edad) 11 12 def __lt__(self, otro): 13 return self.edad < otro.edad 14 15 def __str__(self): 16 return self.__repr__ 17 18 def __repr__(self): 19 return u”({0} tiene {1})” .format(self.nombre, self.edad) 20 21 l = [Edad(‘Luis’, 65), 22 Edad(‘Juan’,28), 23 Edad(‘Montse’, 33),] 24 25 print sorted(l) O bien definimos una función que nos permita extraer el valor a comparar de los objetos: >>> def mi_ordenacion (x): U return x[1] >>> sorted(l, key = U mi_ordenacion) [(‘Juan’,28),(‘Montse’, 33), U (‘Luis’, 65)] >>> O bien podemos emplear una función lambda para generar los valores a com- parar: >>> sorted(l, key = U lambda x: x[1]) [(‘Juan’,28),(‘Montse’, 33), U (‘Luis’, 65)] >>> La primera opción, más clásica de len- guajes como Java o C#, y (supuesta- mente) más limpia, tiene un gran pro- blema. ¿Qué ocurre si queremos ordenar los datos de varias maneras diferentes? El diseñador de sorted sólo empleará una de ellas. Es un enfoque bastante inflexi- ble, es preferible que la función que selecciona el criterio de ordenación sea externa al objeto a ordenar. Además, como se puede observar, esta opción es bastante más compleja.Figura 1: Las variables en Python son nombres.
  • 21. La segunda opción implica el uso de una función externa que nos devuelve el valor a comparar para cada objeto. Indi- camos a sorted qué función usar para seleccionar los valores a comparar mediante el parámetro key. Por último vemos cómo se haría lo mismo con una función lambda. Salta a la vista que la tercera opción es la corta, fácil de leer y elegante (o lo que es lo mismo, la más «pythonic»). El lenguaje de programación Common Lisp se enfrentó a este mismo problema cuando se diseñó su sistema de objetos, y la solución fue la misma: sacar fuera del objeto y de la función de ordenación el código que genere los datos a compa- rar. Python empleó la misma técnica, por lo que mucha gente ve semejanzas entre ambos lenguajes de programación. Cierres Otro de los conceptos que puede provo- car más de un dolor de cabeza es el de cierre. Lenguajes como Javascript giran en torno a este concepto, ya que les per- mite crear algo parecido a objetos, ver Figura 2. En Python, sin embargo, los cierres son la base de una de las caracte- rísticas más usadas del lenguaje última- mente: los decoradores. Un cierre es un trozo de código fuente que depende de variables, algunas de las cuales han sido «capturadas» junto al trozo de código y quedan aisladas de cualquier interferencia externa. En el caso de Javascript, que no posee objetos propiamente dichos, se usan cierres para que una serie de funciones compartan unas variables que no pueden ser accedi- das desde fuera y que por tanto están protegidas. En Python los cierres no funcionan exactamente como lo hacen en otros len- guajes. Siguiendo con las funciones lambda, vamos a crear un cierre con una de ellas: >>> def crea_cierre(num): ... return lambda x=num: x+1 ... >>> cierre = crea_cierre(3) >>> cierre() 4 >>> 4 Analicemos este código. La función crea_cierre() acepta un parámetro num y devuelve una función lambda, por lo que el valor devuelto puede almacenarse en una varia- ble y se comportará como una función. El secreto está en pasar a la función lambda el valor num que queda definido como valor por defecto para x. Lo curioso es que en este caso Python no nos permite pasar ningún valor a la función lambda una vez definida. Si tratamos de pasar un valor: >>> cierre(10) 4 >>> ¡Nos sigue devolviendo 4! No importa qué valor pase- mos a la función, el contenido de x ha quedado completamente cerrado y blo- queado. Por así decirlo, su valor se ha vuelto inaccesible. Si quisiéramos poder cambiar el valor de una variable cerrada, deberíamos usar una función normal en lugar de una función lambda, porque como ya vimos, las funciones lambda no aceptan asignación de variables. ¿Tiene sentido usar cierres en Python? El sistema de objetos de Python es muy sencillo y nada engorroso, por lo que es muy extraño ver el uso de cierres en Python, salvo por una excepción: los decoradores. Un decorador es una fun- ción que intercepta los parámetros de otra función, hace algo y devuelve la función original. Normalmente no se cie- rran variables en un decorador, pero es posible hacerlo. La respuesta de Python a los cierres de funciones son los objetos callable. En Python es posible crear un objeto que se comporte como una función. La función tendrá acceso a una serie de variables de instancia que se pasan en el constructor de la misma: 01 >>> class Saluda(object): 02 ... def __init__(self, saludo): 03 ... self.saludo = saludo 04 ... def __call__(self, nombre): 05 ... print “{0} {1}” .format(self.saludo, nombre) 06 ... 07 >>> saludo = Saluda(‘Hola’) 08 >>> saludo(‘mundo’) 09 Hola mundo 10 >>> saludo = Saluda(‘Hello’) 11 >>> saludo(‘world’) 12 Hello world 13 >>> Creamos un objeto tradicional con la única diferencia de poseer un método llamado __call__, que será el que se eje- cute cuando invoquemos la instancia de la clase como si fuese una función. Pri- mero debemos generar una instancia a la que pasamos la variable de se «cerrará» y posteriormente podemos invocar la ins- tancia como si fuese una función que acepta parámetros como cualquier otra función. Funciones de Primer Orden Como ya hemos dicho, las funciones lambda no son especialmente potentes en Python – en Ruby lo son más – pero nos permiten pasar comportamientos a otras funciones. En teoría de lenguajes de programación, se llama función de primer orden a aquella función que acepta otra función como parámetro, acepta comportamientos además de datos, lo que la hace especialmente potente y flexible. En Python es absolutamente normal usar funciones como parámetros: 01 def saluda(x, f=None): 02 if f: AVANZADOFunciones Lambda 21PYTHONWWW.LINUX- MAGAZINE.ES Figura 2: Cómo funciona un cierre en torno a una función.
  • 22. metros. Primero aplicará la función a «Luis» y «65», después a «Juan» y «28»… y así indefinidamente. map no está limitada a dos listas, podemos emplear tantas lis- tas como queramos: >>> map(lambda x: x.upper(),U [‘Luis’, ‘Juan’U , ‘Montse’]) [‘LUIS’, ‘JUAN’, U ‘MONTSE’] >>> map(lambda x,y,z:U (x, y*z),U [‘Luis’, U ‘Juan’,’Montse’],U [65,28,33], [1,2,3]) [(‘Luis’, 65),U (‘Juan’, 56),U (‘Montse’, 99)] >>> Aunque podríamos pasar cualquier función previa- mente definida, estamos pasando funcio- nes lambda. Es la manera más sencilla y rápida de aplicar map, aunque como ya hemos dicho antes, si necesitamos más de una operación o el código es complejo es mejor definir la función. Este map es el mismo que el del famoso Map/Reduce de Google, con la diferencia de que el de Google se aplica a cientos o miles de máquinas, que aplican funciones map muy complejas a gran cantidad de datos. Pero el concepto es el mismo. Si este es el map… ¿dónde está reduce? >>> reduce(U lambda x,y: x if x[1] > y[1] U else y,U [(‘Luis’, 65), (‘Juan’, 56),U (‘Montse’, 19)]) (‘Luis’, 65) >>> reduce va a aplicar una función de 2 variables a los elementos de una lista con el objetivo de acabar devolviendo un solo elemento. Como su propio nombre indica, reduce una lista a un elemento. Aquí estamos buscando el valor más grande de los presentes en la lista, por lo que la función reductora compara los dos parámetros y siempre devuelve el mayor de ellos. Por lo tanto, map aplica una función a una gran cantidad de datos y reduce realiza alguna operación sobre los datos que los convierte en un solo valor. A pesar de toda la fanfarria existente alrededor de Map/Reduce, lo cierto es que en Python se usan poco. De hecho, reduce dejará de ser una función primi- tiva del sistema en Python 3 y pasará a ser una función de la librería functools, por lo que ha sido degradada a ciuda- dano de segunda fila. Conclusión Estamos tan acostumbrados ya a la pro- gramación orientada a objetos, que se nos olvida que Python en sus inicios tomó prestados gran cantidad de concep- tos y técnicas de otros modelos de pro- gramación. Las funciones lambda no están muy vistas como técnica de pro- gramación, pero las restricciones a las que las somete Python las ha domesti- cado lo suficiente como para que en lugar de entorpecer nuestro código lo hagan más ligero y sencillo de compren- der. ■ 03 print f(x) 04 else: 05 print x 06 >>> 07 >>> saluda(“hola”) 08 hola 09 >>> saluda(“hola”, f=lambda x: x.upper()) 10 HOLA 11 >>> Al fin y al cabo, las variables en Python no son más que nombres que apuntan a «cosas», sin importar demasiado qué son esas cosas. No hay gran misterio en las funciones de primer orden vistas así. Es lo que haces con ellas lo que las vuelve interesantes. Python nos provee de un conjunto de funciones de primer orden, heredadas de otros lenguajes de programación funcionales, que nos per- miten emplear funciones en sus opera- ciones. Map y Reduce Cuando las funciones lambda realmente brillan es cuando se usan en conjunción con las funciones de filtrado y mapeo. Con todo el revuelo generado por Goo- gle y otras empresas en torno a las técni- cas Map/Reduce, es interesante recordar los humildes comienzos de estas técni- cas. El filtrado y mapeo son técnicas here- dadas de la programación funcional, ver Figura 3. En este estilo de programación se evita modificar los datos originales, y en lugar de ello se realizan una serie de transformaciones sobre los datos para ir reduciéndolos y operando sobre los resultados hasta conseguir el resultado deseado. El código resultante suele ser conciso, aunque no siempre fácil de leer y entender. La programación funcional también hace uso de las funciones de primer orden que hemos visto antes. Comencemos por echar un vistazo a la función map: >>> map(lambda x,y: (x,y),U [‘Luis’, ‘Juan’,’Montse’], U [65,28,33]) [(‘Luis’, 65), (‘Juan’, 28), U (‘Montse’, 33)] >>> map aplica una función a dos listas de valores, recorriendo ambas listas de valores y pasando los valores como pará- AVANZADO Funciones Lambda 22 PYTHON WWW.LINUX- MAGAZINE.ES [1] Alonzo Church: http://es.wikipedia. org/wiki/Alonzo_Church Recursos Figura 3: Map y Reduce en acción.
  • 23. No es ni será la última vez que desde esta sección recordemos que la idea ori- ginal de Stallman era la de que cada programa libre estuviese construido sobre librerías de funciones, de manera que su código fuese reutilizable por cualquier otro programa. Quizás en un programa pequeño no sea muy útil este tipo de diseño, pero ¿qué pasa con esos monstruos consum- idores de memoria que rondan por nuestros discos duros? Nos referimos a programas o entornos del calibre de Gnome, KDE, Mozilla u OpenOffice. Todo el mundo se queja de su tamaño excesivo, su alto consumo de recursos y su inexplicable complejidad. Quizás con este artículo desminta- mos este mito y hagamos que el lector mire con nuevos ojos a estos maravi- llosos programas. Grandes Sistemas de Componentes El diseño de un gran programa puede llevar años y cientos o miles de progra- madores. Organizar tal cantidad de per- sonas supone ya una locura sólo por el hecho de asegurarse que todos cobren. Pero vayamos a nuestro mundillo ¿cómo podemos organizarlos para que el desarrollo no acabe en un fiasco? Esta es la gran cuestión no resuelta de la informática, pero, aunque no hayamos encontrado una solución fiable, sí se disponen de técnicas que aumentan la probabilidad de que, al menos, se cree algún software útil. Una de estas técnicas consiste en emplear un sistema de componentes como base para el desarrollo. Un com- ponente es una cantidad de software que ofrece un servicio bien definido y que es reutilizable. Además debe ser posible reutilizarlo «de verdad»: desde cualquier lenguaje y cualquier sitio. Cualquiera que tenga conocimiento sobre cómo funcionan los lenguajes de programación a bajo nivel sabrá que esto es muy muy complicado. Por ello se han desarrollado infraestructuras que nos permiten interactuar con los componentes de manera indirecta. A este software se le suele llamar “mid- dleware” (algo así como “software de en medio”). Ejemplos famosos de Middleware son J2EE, que muchos conocerán, y CORBA, que a muchos les gustaría no conocer. Ambos son sistemas enormes y costosos que relegan al programador a mera herramienta en manos de inge- nieros, denominados arquitectos, que conocen su compleja infraestructura. Pero los sistemas de componentes también se emplean en software libre y han dado buenos resultados. Quizás el más desconocido es UNO, de Universal Network Objects, el sistema que emplea OpenOffice, ver Listado [1], y que SUN desarrolló para su precursor: StarOffice. PyUNO Un sistema de componentes con el que sólo se pueda programar en un lenguaje no tiene mucha utilidad. Por eso en OpenOffice se han asegurado de fomentar la creación de interfaces a distintos lenguajes de programación. Podemos acceder a UNO usando Javascript, Java, Ruby, Perl o Python (ver Recurso [2]). PyUNO es el nombre de la interfaz y podremos encontrarlo sin problemas en nuestra distribución de Linux. Eviden- temente, necesitamos también tener instalado OpenOffice. En este artículo hemos realizado los programas usando OpenOffice 2.0, que cambió la interfaz respecto a la versión 1.0, y la versión de PyUNO 0.7.0. Un Ejemplo Rápido Vamos a crear el famoso «Hola mundo» con PyUNO. Para ello primero debemos arrancar OpenOffice con el siguiente comando desde el directorio donde esté instalado: $> ./sofficeU "-accept=socket,U INTEGRACIÓNOpenOffice 23PYTHONWWW.LINUX- MAGAZINE.ES PyUNO: Explota todo el potencial de OpenOffice Python no hay más que UNO¿Has visto alguna vez a los brokers de bolsa? ¿Recuerdas sus sofisticados y caros programas para ver las cotizaciones de las empresas en bolsa en tiempo real? Nos- otros haremos lo mismo con 70 lineas de código Python, OpenOffice y la tecnología UNO de OpenOffice. Por José María Ruíz
  • 24. INTEGRACIÓN OpenOffice 24 PYTHON WWW.LINUX- MAGAZINE.ES host=localhost,U port=2002;urp;" Al arrancar OpenOffice se arranca su sistema de componentes. Podemos pen- sar en este proceso como en el arranque de un servidor, sólo cuando esté funcionando podrán los clientes trabajar con él. Las opciones que pasamos son para que se cree un socket y se escuche en localhost en el puerto 2002. Por defecto OpenOffice no abre el socket, de ma- nera que no podrán controlar nuestro OpenOffice sin nuestro consentimiento. OpenOffice incorpora de serie varios intérpretes de lenguajes, entre ellos uno de Python que ya viene preconfig- urado para poder hacer uso de la libr- ería UNO. Está junto al resto de eje- cutables de OpenOffice, así que lo eje- cutaremos desde allí. El programa que usaremos se encuentra en el Listado [2]. El proceso es el siguiente: • Obtenemos un contexto local (un sitio donde guardar los datos de la conexión) • Arrancamos el componente UnoUrl- Resolver que nos sirve para acceder a otro OpenOffice en otro equipo (en nuestro caso accederemos a nuestro propio equipo) • Emplearemos el objeto resolver para acceder al OpenOffice remoto • Arrancamos un «Desktop» (escrito- rio) de OpenOffice (esto es, una instancia de OpenOffice vacía) • Arrancamos un SWriter (es decir, el procesador de textos) en el escrito- rio • Obtenemos un cursor, con el que podremos posicionarnos dentro del texto • e insertamos texto en el cursor El resultado, no muy espectacular, podemos verlo en la Figura [1]. Ya te- nemos nuestro «hola mundo» insertado en SWriter. ¿Demasiado código? Piensa por un momento lo que estamos haciendo. 01 import uno 02 03 localContext = uno.getComponentContext() 04 resolver = localContext.ServiceManager.createInstanceWithContext (“com.sun.star.bridge.UnoUrlResolver”, localContext ) 05 ctx = resolver.resolve( “uno:socket,host=localhost,port=2002;urp; StarOffice.ComponentContext” ) 06 desktop = ctx.ServiceManager.createInstanceWithContext( “com.sun.star.frame.Desktop”,ctx) 07 doc = desktop.loadComponentFromURL(“private:factory/swriter”,”_blank”,0,()) 08 cursor = doc.Text.createTextCursor() 09 doc.Text.insertString( cursor, “Hola Mundo”, 0 ) 10 ctx.ServiceManager Listado 1: Programa «Hola Mundo» 01 import uno 02 import random 03 import time 04 import httplib 05 import csv 06 07 class Calc: 08 def __init__(self): 09 self.conecta() 10 11 def conecta (self): 12 self.local = uno.getComponentContext() 13 self.resolver = self.local.ServiceManager. createInstanceWithContext (“com.sun.star.bridge.UnoUrlResolver”, self.local) 14 self.context = self.resolver.resolve(“uno:socket,host= localhost,port=2002; urp;StarOffice.ComponentContext”) 15 self.desktop = self.context.ServiceManager. createInstanceWithContext (“com.sun.star.frame.Desktop”, self.context) 16 #self.doc = self.desktop.getCurrentComponent() 17 self.doc = self.desktop.loadComponentFromURL (“private:factory/scalc”,”_blank”,0,()) 18 self.hojas = self.doc.getSheets() 19 self.s1 = self.hojas.getByIndex(0) 20 21 def actualiza(self, cotizacion, fila): 22 23 i = 0 24 for entrada in cotizacion: 25 if (i == 0) or (i == 2) or (i ==3): 26 self.s1.getCellByPosition(i,fila). setString(entrada) 27 else: 28 self.s1.getCellByPosition(i,fila).setValue (float(entrada)) 29 30 i = i + 1 31 32 def getSimbolo(simbolo): 33 c = httplib.HTTPConnection(“finance.yahoo.com”) 34 c.request(“GET”, ”/d/quotes.csv?s=”+simbolo+”&f=sl1d1t1c1ohgv& e=.csv”) 35 r = c.getresponse() 36 cad = r.read() 37 reader = csv.reader([cad]) 38 resultado = [] 39 for row in reader: 40 resultado = row 41 return resultado 42 43 if __name__ == ‘__main__’: 44 45 simbolos = [“GOOG”,”MSFT”,”RHAT”] 46 47 c = Calc() 48 49 while(1): 50 i = 0; 51 for s in simbolos: 52 c.actualiza(getSimbolo(s),i) 53 i = i + 1 54 55 time.sleep(10) Listado 2: «OfficeBroker»
  • 25. Hemos levantado dos componentes y hecho acceso remoto a otro OpenOf- fice. Este segundo OpenOffice puede estar en una máquina al otro lado del mundo. Es algo bastante impresionan- te, pero por el momento poco útil. Veamos un poco más sobre UNO antes de realizar un programa más útil. Arquitectura de UNO OpenOffice está implementado en C++. UNO se usa internamente para realizar cualquier cosa. Básicamente, OpenOffice no es más que una gran cantidad de componentes que interac- túan entre sí. Todo dentro de OpenOf- fice es un componente, así que podemos acceder a cualquier parte de la aplicación, ¡incluso reconstruir OpenOffice en Python! Los sistemas de componentes usan un registro de componentes al que se le puede pedir que arranque compo- nentes. El registro localiza el compo- nente en disco y lo carga en memoria, de manera que puede ser usado. Las llamadas a las funciones no se realizan directamente, sino que se suele emplear algún sistema no dependiente de lenguaje o plataforma, como puede ser XML o un formato ASCII. El registro también debe ser capaz de gestionar los recursos que consume el componente, descargándolo de memo- ria cuando ya no sea necesario. Los componentes pueden ser progra- mados en cualquier lenguaje con el que se tenga interfaz. Un componente es un conjunto de ficheros que proporcionan un servicio. Se acompañan de un fichero XML que describe su funcional- idad. Lo mejor es que podemos vincu- lar ese servicio a algún componente gráfico, como por ejemplo un botón o menú. Comenzaremos por realizar un pro- grama que funcionará de manera externa a OpenOffice, y después creare- mos un componente con él y lo inte- graremos en OpenOffice. Nuestro Programa de Stocks Comencemos con la parte útil, ver Lis- tado [2]. Vamos a crear un sistema que nos permita controlar las acciones de una serie de empresas que están en bolsa dentro de un índice tecnológico, el Nasdaq (para algo estamos en una revista de informática), usando la hoja de cálculo SCalc y un programa Python. Nuestro programa accederá usando Internet a un sitio web donde podrá recoger los datos en CSV (Valores Sepa- rados por Comas), los procesará y los introducirá en SCalc. Comenzaremos por crear una fun- ción que recoja el fichero CSV y lo pro- cese. Lo que hacemos es conectarnos con la página web finance.yahoo.com. Yahoo tiene un sitio web bastante avanzado sobre cotizaciones de bolsa, y uno de sus servicios nos permite recoger los datos de cotización de una empresa en tiempo real en formato CSV. Sin embargo, Yahoo no nos per- mitirá acceder a los datos demasiado a menudo, ya que dispone de un servi- cio de pago para ello, así que puede cortarnos el «grifo» en cualquier momento si hacemos demasiadas con- sultas por minuto. Por eso recogere- mos los datos cada 10 segundos. La función getSimbolo() se encargará de ello. Ahora ya tenemos los datos, tenemos que mandarlos a SCalc. Hemos creado un objeto llamado Calc para gestionar el acceso. Hemos metido en el método constructor (__init__) el código que conecta con OpenOffice, puesto que sólo lo haremos una vez. Una hoja de cálculo posee varias «hojas», así que tendremos que solicitar una usando el método getSheets(), que nos devuelve una lista con las distintas hojas. Dentro de esta lista usaremos getByIndex() para seleccionar la primera hoja, que es la que se ve cuando arrancamos SCalc. El método actualiza() admite una lista con los datos de cotización y número que representa la fila donde aparecerá en SCalc. Una hoja de cálculo se compone de celdas, y éstas tienen un tipo. La función getCellByPosition() nos permite acceder a una celda pasándole la columna y la fila (al revés de lo nor- mal, así que cuidado). Una vez localizada la celda, tenemos varias funciones para poder asignar un valor: • setString(): para poner una cadena • setValue(): para poner un número • setFormula(): para poner una fór- mula El dato cotización es la lista de parámetros de cotización, pero vienen dados como cadenas de caracteres. Las posiciones 0, 2 y 3 son realmente cade- nas, pero el resto son números. Por eso tenemos que convertir ciertos valores al tipo float() mediante la función float(). El resultado se puede ver en la Figura [2]. Observamos cómo se abre una ven- tana de SCalc y se rellena con los val- INTEGRACIÓNOpenOffice 25PYTHONWWW.LINUX- MAGAZINE.ES Figura 1: Un documento de Write de OpenOffice con el ineludible “Hello World” generado a partir de PyUNO. Figura 2: El programa examina los valores de la bolsa NASDAQ de Yahoo a intervalos regulares y los inserta en una hoja de cálculo.