Patricio Páez Serrato
9 de Abril de 2004
Este documento fué creado el 8 de Abril de 2004. Primera publicación el 27 de Junio de 2004.
| Para sugerencias,correcciones | patriciopaez |
| o preguntas acerca de este | en |
| documento, escribir a: | hotmail punto com |
El original de este documento se encuentra en http://pp.com.mx/python
Derechos Reservados (c) Patricio Páez Serrato, México 2004.
La primera parte de este documento es una referencia del lenguaje Python, con enlaces a páginas de interés (se encuentra en http://pp.com.mx/python). Esta segunda parte recopila los ejemplos que he mostrado cuando imparto el Tutorial de Python. Empiezan por algo muy sencillo, y combinando hasta llegar a algo más complejo. No por ser sencillos dejan de ser útiles, y como menciono durante el tutorial: los resultados de estos ejemplos pueden crecer y convertirse en sus propios conjuntos de herramientas.
Los ejemplos pueden realizarse tanto en una PC con MS-Windows, Unix o Linux siempre y cuando Python corra. Pueden usarse las versiones 1.5.2, y 2.0 en adelante. Los ejemplos tratan conceptos generales y procuran no usar características únicas en las versiones más recientes.
Todos los ejemplos, excepto las interfases gráficas pueden hacerse en modo texto, usando preferentemente un editor que resalte la sintaxis de Python como Vim, emacs, Scite y otros. Los usuarios de MS-Windows pueden instalar algunos de estos editores del CD Gnuwin.
Los ejemplos con Tkinter requieren tener el conjunto de funciones gráficas Tk así como el modulo de Python Tkinter que lo accesa. Ambos vienen incluídos en el instalador de Python para MS-Windows y se instalan cuando se aceptan todas las opciones del instalador sin modificación. En Linux el lector puede verificar mediante este comando:
tk-8.3.3-7mdk
tkinter-2.1.1-3mdk
Programar en Python puede hacerse de varias maneras según la necesidad o el gusto de cada persona. Para los neófitos mi recomendación es que utilicen el ambiente gráfico interactivo llamado idle. Esta herramienta viene incluída con el módulo tkinter. Además de resaltar la sintaxis en colores, permite editar archivos fuente y es más amigable al inicio.
El idle tiene dos ambientes: el shell interactivo con título *Python Shell* en su ventana; muestra el prompt >>> y espera un comando, y uno o más editores que se abren con el menú File -> New Window. Cada editor empieza con el título Untitled en su ventana, el cual cambia hasta que se salva a un archivo con File -> Save As (y subsecuentemente File -> Save). Cada editor nos permite ejecutar el código Python que contiene.
Se recomienda crear una carpeta para realizar y guardar los ejemplos. Para correr idle, cambiar primero a esa carpeta y entonces correr idle: En MS-Windows:
Una vez que ya teclearon y funcionaron las cosas, entonces copien del shell interactivo y peguen a una ventana de editor y salven en un archivo con terminación .py para que conserven lo que hicieron para la posteridad.
Podemos explorar los enteros largos de Python si hacemos una tabla
de potencias de 2, evaluando 2
mientras n varía
de 0 a n.
print n, 2**n
0 1 1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024 11 2048 12 4096 13 8192 14 16384 15 32768 16 65536 17 131072 18 262144 19 524288 20 1048576 21 2097152 22 4194304 23 8388608 24 16777216 25 33554432 26 67108864 27 134217728 28 268435456 29 536870912 30 1073741824 31 2147483648 32 4294967296 33 8589934592 34 17179869184 35 34359738368 36 68719476736 37 137438953472 38 274877906944 39 549755813888 40 1099511627776 41 2199023255552 42 4398046511104 43 8796093022208 44 17592186044416 45 35184372088832 46 70368744177664 47 140737488355328 48 281474976710656 49 562949953421312 50 1125899906842624 51 2251799813685248 52 4503599627370496 53 9007199254740992 54 18014398509481984 55 36028797018963968 56 72057594037927936 57 144115188075855872 58 288230376151711744 59 576460752303423488
12345678901234L
OverflowError: integer literal too large
print n, 2L**n
Los números muy grandes son difíciles de entender sin las comas que normalmente usamos. Vamos entonces a definir una función que agregue las comas. Los pasos necesarios serían:
def poncoma( n ):
"Regresa n como cadena con comas."
s = str(n)
pos = len(s)
while pos > 3:
pos = pos - 3
s = s[:pos] + ',' + s[pos:]
return s
for n in range(60):
print '%3d %30s' % ( n, poncoma( 2**n ) )
El resultado será ahora más legible:
0 1 1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1,024 11 2,048 12 4,096 13 8,192 14 16,384 15 32,768 16 65,536 17 131,072 18 262,144 19 524,288 20 1,048,576 21 2,097,152 22 4,194,304 23 8,388,608 24 16,777,216 25 33,554,432 26 67,108,864 27 134,217,728 28 268,435,456 29 536,870,912 30 1,073,741,824 31 2,147,483,648 32 4,294,967,296 33 8,589,934,592 34 17,179,869,184 35 34,359,738,368 36 68,719,476,736 37 137,438,953,472 38 274,877,906,944 39 549,755,813,888 40 1,099,511,627,776 41 2,199,023,255,552 42 4,398,046,511,104 43 8,796,093,022,208 44 17,592,186,044,416 45 35,184,372,088,832 46 70,368,744,177,664 47 140,737,488,355,328 48 281,474,976,710,656 49 562,949,953,421,312 50 1,125,899,906,842,624 51 2,251,799,813,685,248 52 4,503,599,627,370,496 53 9,007,199,254,740,992 54 18,014,398,509,481,984 55 36,028,797,018,963,968 56 72,057,594,037,927,936 57 144,115,188,075,855,872 58 288,230,376,151,711,744 59 576,460,752,303,423,488
Hace años al Departamento de Informática se le llamaba de Procesamiento Electrónico de Datos (Electronic Data Processing en Inglés, con las siglas EDP). El nombre antiguo era más descriptivo de la labor que se supone debían realizar las computadoras. Aquí mostraremos cómo hacemos esto en Python, con un conjunto de datos pequeño pero real.
Tenemos la siguiente información en el archivo capitales.txt:
México,D.F. Aguascalientes,Aguascalientes Tijuana,Baja California Mexicali,Baja California Sur Campeche,Campeche Tuxtla Gutiérrez,Chiapas Chihuahua,Chihuahua Saltillo,Coahuila Colima,Colima Durango,Durango Toluca,Edo. de México Chilpancingo,Guerrero Guanajuato,Guanajuato Pachuca,Hidalgo Guadalajara,Jalisco Morelia,Michoacán Cuernavaca,Morelos Tepic,Nayarit Monterrey,Nuevo León Oaxaca,Oaxaca Puebla,Puebla Querétaro,Querétaro Chetumal,Quintana Roo Culiacán,Sinaloa Hermosillo,Sonora San Luis Potosí,San Luis Potosí Villa Hermosa,Tabasco Tampico,Tamaulipas Tlaxcala,Tlaxcala Jalapa,Veracruz Mérida,Yucatán Zacatecas,Zacatecas
A continuación vamos a leer esta pequeña 'base de datos' a una cadena en Python, la vamos a convertir a una lista de registros, luego separaremos los campos de cada registro. El lector puede ir haciendo primero estos pasos en forma interactiva, revisando los resultados:
# Leemos el archivo a una cadena:
f = open( 'capitales.txt' )
datos = f.read()
# Partimos la cadena a una lista cuyos elementos son
# los registros de nuestra 'base de datos'
import string
lista = string.split( datos, '\n' )
print lista
# Convertimos cada elemento de la lista a una pareja,
# usamos una función lambda:
pares = map( lambda e: string.split( e, ','), lista )
print pares
# Podemos crear una lista para cada campo:
# una lista de capitales y otra lista de estados.
# Esta es una forma de obtenerlas:
capitales = []
estados = []
for capital,estado in pares:
capitales.append( capital )
estados.append( estado )
# Cómo determinar los nombres únicos de ambas listas?
# Usamos la concatenación de listas.
unicos = []
for nombre in capitales+estados:
if nombre not in unicos:
unicos.append(nombre)
else:
print nombre
# Cuántos elementos tenemos?
print len(unicos)
# Los ordenamos alfabéticamente:
unicos.sort()
print unicos
def leedatos( nombrearchivo ):
"Abre un archivo, lee y regresa un arreglo."
f = open( nombrearchivo )
renglones = f.readlines()
arreglo = map( lambda x: x.split(','), renglones )
return arreglo
matriz = leedatos( 'capitales.txt' )
for renglon in matriz:
for celda in renglon:
print '%-20s' % celda,
print
Hoy en día usar HTML es cosa del diario, cuando navegamos en internet, leemos correo, y cada vez son más las aplicaciones que usan el navegador como punto de acceso al usuario. Muchas páginas de HTML se generan por programas, no por personas. Por esta razón vamos a practicar con Python.
Un documento básico de HTML puede ser así:
<html> <head><title>página hecha a mano</title></head> <body> <h1>Hola...</h1> probando<br> </body> </html>
Vamos a dividir el documento HTML en las partes que lo forman, tomando como base la muestra anterior:
---------- inicio del documento ---------- <html> <head><title>página hecha a mano</title></head> <body> ---------- cuerpo del documento ---------- <h1>Hola...</h1> probando<br> ---------- final del documento ---------- </body> </html>
Finalmente desarrollamos tabla() que será muy utilizada para mostrar arreglos. No es necesario utilizar variables i, j como en otros lenguajes para recorrer el arreglo, ni saber las dimensiones. Cada renglón del arreglo puede ser de distinta longitud.
Tenemos el siguiente código con las funciones básicas:
def inicio( cadena='' ):
"Inicia el documento HTML."
return '''<html>
<head>
<title>''' + cadena + '''</title>
</head>
<body>\n'''
def encabezado( nivel='1', string='' ):
"Regresa string con encabezado o título HTML, default es H1."
return '<h'+ nivel + '>'+ string + '</h'+ nivel + '>'
def horizontal():
"Línea horizontal en el documento HTML."
return '<hr />'
def destino( clave, texto ):
"Regresa texto como destino."
return '<a name="' + clave + '>' + texto + '</a>'
def liga( url, texto):
"Liga o hipervínculo a url con texto."
return '<a href="' + url + '">' + texto + '</a>'
def parrafo( texto ):
"Genera un párrafo con texto."
return '<p>' + texto + '</p>\n'
def saltolinea():
"Genera un salto de línea."
return '<br>\n'
def tabla( arreglo ):
"""Muestra arreglo en una tabla HTML.
Las celdas pueden ser cualquier tipo, se convierten a cadena siempre."""
temp = '<table border="1">\n'
for renglon in arreglo:
temp = temp + '<tr>'
for celda in renglon:
temp = temp + '<td>' + str(celda) + '</td>\n'
temp = temp + '</tr>\n'
return temp + '</table>\n'
def final():
"Fin del documento HTML."
return '''</body>
</html>'''
print inicio( 'Página dinamica')
print encabezado( 'Página generada con Python')
print parrafo( 'Tenemos a continuación una tabla:')
print tabla( [ ['r1c1', 'r1c2'],
['r2c1', 'r2c2'] ] )
print final()
Las funciones que definimos pueden anidarse. Por ejemplo:
+ 'tiene mucha información sobre Python.' )
El sitio www.python.org tiene mucha información sobre Python.Para probar nuestros experimentos necesitamos enviar la salida del programa a un archivo que podemos llamar prueba.html. Para hacer esto, necesitamos correr nuestro guión html.py con un comando así:
def hacertabla( ren=10, col=10, operador='+'):
"""Construye y regresa un arreglo ren x col.
Cada celda toma un valor que depende de x,y y el
valor de operador. El arreglo es de 10 x 10 si
no se suministran los valores de ren y col."""
array = []
for ren in range(1, ren+1):
array.append( [] )
for col in range( 1, col+1):
dato = calcula(ren, col, operador)
array[-1].append( dato )
return array
def calcula( a, b, operador):
"Regresa una cadena tipo 'a operador b = resultado'."
if operador == '+':
return str(a) + ' + ' + str(b) + ' = ' + str( a+b)
elif operador == '*':
return str(a) + ' * ' + str(b) + ' = ' + str( a*b)
def leedatos( nombrearchivo ):
"Abre un archivo, lee y regresa un arreglo."
f = open( nombrearchivo )
renglones = f.readlines()
arreglo = map( lambda x: x.split(','), renglones )
return arreglo
print inicio( 'Mi primera página dinamica')
print encabezado( 'Página generada con Python')
print parrafo( 'Algunos ejemplos de las rutinas para generar HTML')
print tabla( leedatos( 'capitales.txt' ) )
print encabezado( 'Tabla de sumas' )
print tabla ( hacertabla() )
print encabezado( 'Tabla de multiplicación' )
print parrafo( 'Esta tabla usa la misma función con otro contenido' )
print tabla ( hacertabla(12, 9, '*'), )
print final()
El siguiente paso es definir una clase que llamaremos buffer. Esto representa mejoras respecto a nuestro ejemplo anterior, porque ahora podremos escribir el texto HTML a un archivo desde el programa sin redireccionar la salida estándar. Esto nos permite generar más de una página simultáneamente.
La clase buffer crea un atributo text en cada instancia que es el texto HTML que se va formando. El método add() se usa para agregar texto a la instancia, mientras que el método pop() es para regresar y vaciar el atributo de texto, como cuando lo vamos a escribir a un archivo.
La clase tiene también métodos con los mismos nombres que las funciones básicas. Estos métodos simplemente llaman a la función correspondiente y van agregando el texto regresado mediante el método add().
class buffer:
"""Clase para generar objetos que almacenan codigo HTML
que despues sera escrito a algun archivo."""
def __init__( self ):
"Constructor, crea el atributo de texto."
self.text = ''
def add( self, texto ):
"Agrega texto arbitrario al buffer."
self.text = self.text + texto
def pop( self ):
"Regresa el texto del buffer, y borra el buffer."
temp = self.text
self.text = ''
return temp
def inicio( self, titulo ):
"Inicia el documento HTML."
self.add( inicio( titulo ) )
def encabezado( self, nivel, string):
"Regresa string con encabezado o título HTML, default es H1."
self.add( encabezado( nivel, string ) )
def horizontal( self ):
"Línea horizontal en el documento HTML."
self.add( horizontal() )
def destino( self, clave, texto ):
"Regresa texto como destino."
self.add( destino( clave, texto) )
def liga( self, url, texto):
"Liga o hipervínculo a url con texto."
self.add( liga( url, texto) )
def parrafo( self, texto ):
"Genera un párrafo con texto."
self.add( parrafo( texto) )
def saltolinea( self ):
"Genera un salto de línea."
self.add( saltolinea() )
def tabla( self, arreglo ):
"Inserta arreglo en una tabla HTML."
self.add( tabla( arreglo ) )
def final( self ):
"Fin del documento HTML."
self.add( final() )
import html # Crear dos instancias de la clase buffer: pagina1 = html.buffer() pagina2 = html.buffer() # Llenar cara buffer: pagina1.inicio( 'Página 1' ) pagina1.encabezado( '2', 'Esta es página 1') pagina1.liga( 'pag2.html', 'Ir a página 2' ) pagina1.final() pagina2.inicio( 'Página 2' ) pagina2.encabezado( '2', 'Esta es Página 2') pagina2.liga( 'pag1.html', 'Ir a página 1' ) pagina2.final() # Vaciar cada buffer a un archivo: fp = open( 'pag1.html', 'w' ) fp.write( pagina1.pop() ) fp = open( 'pag2.html', 'w' ) fp.write( pagina2.pop() )
De los varios conjuntos de herramientas para hacer interfases gráficas, veremos Tk. Tk es el conjunto de herramientas que se hizo originalmente para el lenguaje de guiones TCL. Mediante el módulo Tkinter, Python puede utilizar Tk.
Para trabajar con un cualquier juego de herramientas gráficas, necesitamos ir creando las ventanas o elementos (llamados también widgets) que usaremos, los cuales quedan en una jerarquía. En primer nivel tendremos una ventana principal, a la cual agregamos botones, un marco, un cuadro de texto, etc.
Los pasos para todo programa gráfico serán:
raiz = Tk()
w = Label(raiz)
w.pack()
w[ 'text' ] = 'Hola mundo'
raiz.mainloop()
El widget de texto Text() nos da la base para hacer un editor. Esta clase Text() tiene los métodos insert() y get() para mostrar y tomar de vuelta texto:
from Tkinter import * import sys raiz = Tk() editor = Text(raiz) editor.pack() f = open( sys.argv[1] ) editor.insert( '1.0', f.read() ) raiz.mainloop()
from Tkinter import *
import sys
def quit(event ):
"Termina la aplicación."
raiz.quit()
def save(event):
"Salva el texto del editor."
f = open( nombrearchivo, 'w' )
f.write( editor.get( '1.0', END) )
f.close()
print 'archivo', nombrearchivo, 'salvado.'
raiz = Tk()
editor = Text(raiz)
editor.pack()
editor.bind( '<Control-q>', quit )
editor.bind( '<Control-s>', save )
if len(sys.argv)>1:
nombrearchivo = sys.argv[1]
try:
f = open( nombrearchivo )
except:
print 'no pudo abrir archivo', nombrearchivo
editor.insert( '1.0', f.read() )
else:
print 'falta nombre de archivo'
sys.exit()
mainloop()
Python nos permite hacer aplicaciones que incluyan un servidor de HTTP. Puede ser en la intranet de nuestra casa u oficina, o bien en internet. Un servidor básico de HTTP, al cual podemos modificar si deseamos, empieza así:
import BaseHTTPServer, SimpleHTTPServer
httpd = BaseHTTPServer.HTTPServer( ( '', 80),
SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.serve_forever()
Para añadir CGI utilizamos SimpleCGIHTTPRequestHandler en lugar de SimpleHTTPRequestHandler en nuestra instancia de servidor:
import BaseHTTPServer, CGIHTTPServer
httpd = BaseHTTPServer.HTTPServer( ( '', 80),
CGIHTTPServer.CGIHTTPRequestHandler)
httpd.serve_forever()
Ambos casos pueden probarse en tu máquina tratando de mostrar la dirección http://localhost en un navegador. Podrás ver los archivos que estén en el directorio de trabajo al momento de correr el guión servidor. Mientras el guión corre, arroja una bitácora de los accesos. En Linux es necesario que estés como root para correr estos guiones.
Roundup es un ejemplo de una aplicación hecha en Python que crea su servidor HTTP con CGI. Ver http://roundup.sf.net para más información.
Documentar nuestros programas, módulos y ejemplos en Python no representa un esfuerzo adicional si hemos incluído las cadenas de documentación. Para el caso de un módulo, podemos incluir las siguientes cadenas:
Puede tener una línea de encabezado,
y después uno o más párrafos de explicación...'''
__author__ = 'xxxx xxxx'
__date__ = 'xxxx xxxx'
__version__ = 'xxxx xxxx'
__credits__ = 'xxxx xxxx'
__text__ = 'xxxx xxxx'
__file__ = 'xxxx xxxx'
Se recomienda al final de un módulo definir una función prueba() que llame algunas de las funciones para validar que todo está bien. Esta función deberá correr solamente cuando el módulo se carga como guión principal, no cuando se importa desde otro archivo. Para lograr esto, usar el siguiente código:
prueba()