Вы находитесь на странице: 1из 142

http://www.maestrosdelweb.

com/guias/#guia-python

Gua Python
Python es uno de los lenguajes de programacin multiparadigma, ms potente y que menor curva de
aprendizaje demanda. Con Python ...
Visita Gua Python para mas informacin.

Captulos
1.

Programacin Orientada a objetos en Python

2.

Mtodos y Propiedades en Python

3.

Listas, tuplas, diccionarios y estructuras de control

4.

Trabajando con templates, archivos y condicionales

5.

Excepciones, helpers y refactoring

6.

Herencia, relacin entre dos o ms clases

7.

Testeando cdigo con doctest en los comentarios

8.

Qu te gustara aprender en el prximo captulo?

9.

Interfaces grficas con wxPython

10.

Finalizando con Python y MySQL

11.

Dos hroes de Python nos cuentan sus experiencias

12.

Cmo se utiliza Python y Django en Mejorando.la

13.

Sigamos aprendiendo Python

14.

Conociendo a fondo el repositorio de Mejorando.la creado con Python y Django

15.

Gua Python: Conociendo a detalle las secuencias

16.

Ventajas para los que se ponen la camiseta de python

17.

Gua Python: Cadenas de texto

18.

Gua Python: Expresiones Regulares

19.

Gua Python: Manejando archivos, diccionarios y funciones

PROGRAMACIN ORIENTADA A OBJETOS EN PYTHON

Python es uno de los lenguajes de programacin multiparadigma, ms potente y que


menor curva de aprendizaje demanda. Con Python puedes crear tanto robustas
aplicaciones de escritorio como Web, con muy pocas lneas de cdigo y en muy poco
tiempo. En esta gua te propongo aprender Python programando a lo grande Te
animas al desafo?

EL DESAFO
Comenzaremos programando con pocas introducciones. El objetivo, es que desde el
comienzo, tomes tu editor de textos favoritos, te sientes a programar a la par de cada
captulo, ejecutes tus cdigos y aprendas mientras programas.
Al final de cada captulo, encontrars un chuleta con el resumen de lo que habrs
aprendido. Y con tan solo 90 por captulo, en 15 horas estars en condiciones de
programar, como un verdadero Pythonista.

QU NECESITAS?
Un editor de textos
Pues desempolva tu legendario editor de textos, ese favorito que has tenido por
siempre. No tienes un editor de textos favorito? Si tienes un S.O. GNU/Linux chale
un vistazo a esta lista de editores de texto para Linux. En cambio si utilizas Windows,
puedes descargar Notepad++ para Windows
Instalar Python
Si utilizas un SO GNU/Linux, seguramente ya tienes Python instalado. Para comprobarlo,
abre una terminal y simplemente escribe:

python

y pulsa enter.
Nota: Si utilizas MacOS X, el procedimiento para comprobar si tienes Python instalado,
es el mismo.
Aparece un texto como este?

Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)


[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

Entonces Tienes Python instalado!


No ves el texto anterior?
Entonces escribe:

sudo apt-get install python

Y Listo! Sigue las instrucciones en pantalla y tendrs Python instalado.


En cambio, si utilizas Windows puedes lee el tutorial completo de instalacinInstalando
Python en Windows de Ricardo Azpeitia en Foros del Web.
Ahora s, ests listo? A programar!

CAPTULO I: PRIMEROS PASOS CON PYTHON


Hagamos algo til. Crearemos un mdulo Python mediante el cual, nos pida algunos
datos y con ellos, nos imprima un presupuesto para enviarle nuestros clientes.

MDULO
Un mdulo es un archivo escrito en Python, con extensin .py

El resultado final tras ejecutar el mdulo que crearemos, ser similar al siguiente:

Este ser el resultado de nuestro primer mdulo hecho en Python

1. Abre el editor de textos


2.
3.
4.
5.
6.

Copia el cdigo que est ms abajo


Guarda el archivo como presupuesto.py
Abre una terminal/consola
Navega hasta el directorio donde haz guardado el archivo
Ahora escribe python presupuesto.py y ve como funciona.

TIP
Un mdulo python puede ejecutarse mediante una terminal escribiendo:
python nombre_del_archivo.py

CDIGO FUENTE QUE DEBES COPIAR Y PEGAR EN EL ARCHIVO


PRESUPUESTO.PY

# -*- coding: utf-8 -*-

class ModeloDePresupuesto:
# Datos comerciales
titulo = "PRESUPUESTO"
encabezado_nombre = "Eugenia Bahit"
encabezado_web = "www.eugeniabahit.com.ar"
encabezado_email = "mail@mail.com"

# Datos impositivos
alicuota_iva = 21

# Propiedades relativas al formato


divline = "="*80

# Setear los datos del cliente


def set_cliente(self):
self.empresa = raw_input('\tEmpresa: ')
self.cliente = raw_input('\tNombre del cliente: ')

# Setear los datos bsicos del presupuesto


def set_datos_basicos(self):
self.fecha = raw_input('\tFecha: ')
self.servicio = raw_input('\tDescripcin del servicio: ')

importe = raw_input('\tImporte bruto: $')


self.importe = float(importe)
self.vencimiento = raw_input('\tFecha de caducidad: ')

# Calcular IVA
def calcular_iva(self):
self.monto_iva = self.importe*self.alicuota_iva/100

# Calcula el monto total del presupuesto


def calcular_neto(self):
self.neto = self.importe+self.monto_iva

# Armar el presupuesto
def armar_presupuesto(self):
"""
Esta funcin se encarga de armar todo el presupuesto
"""
txt = '\n'+self.divline+'\n'
txt += '\t'+self.encabezado_nombre+'\n'
txt += '\tWeb Site: '+self.encabezado_web+' | '
txt += 'E-mail: '+self.encabezado_email+'\n'
txt += self.divline+'\n'

txt += '\t'+self.titulo+'\n'
txt += self.divline+'\n\n'
txt += '\tFecha: '+self.fecha+'\n'
txt += '\tEmpresa: '+self.empresa+'\n'
txt += '\tCliente: '+self.cliente+'\n'
txt += self.divline+'\n\n'
txt += '\tDetalle del servicio:\n'
txt += '\t'+self.servicio+'\n\n'
txt += '\tImporte: $%0.2f | IVA: $%0.2f\n' % (
self.importe, self.monto_iva)
txt += '-'*80
txt += '\n\tMONTO TOTAL: $%0.2f\n' % (self.neto)
txt += self.divline+'\n'
print txt

# Mtodo constructor
def __init__(self):
print self.divline
print "\tGENERACIN DEL PRESUPUESTO"
print self.divline
self.set_cliente()
self.set_datos_basicos()

self.calcular_iva()
self.calcular_neto()
self.armar_presupuesto()

# Instanciar clase
presupuesto = ModeloDePresupuesto()

ENTENDIENDO EL CDIGO
Expliquemos el cdigo paso a paso:

ENCONDING DEFINIR CODIFICACIN DE CARACTERES

# -*- coding: utf-8 -*-

Python necesita que le indiquemos la codificacin de caracteres que utilizaremos.


Entonces, lo indicaremos en la primera lnea del cdigo.

ENCODING
Debe ser la primera lnea del cdigo
Sintaxis: # -*- coding: CODIFICACION -*-

CLASES EN PYTHON

class ModeloDePresupuesto:

En la programacin, un objeto es una entidad provista de mtodos (funciones) y


atributos. Haciendo un paralelismo con la realidad, podemos decir que:
Una persona, realiza varias acciones (funciones) como caminar, saltar, correr, comer,
dormir, etc. y tiene diferentes atributos como el color de pelo, su estatura, su peso, el
color de sus ojos, etc.
Pero, decir persona es muy abstracto, pues yo no soy persona, todos somos
personas. Yo soy Eugenia, tu eres Jos o no te llamas Jos?, tu madre es Ana (a qu
adivino nuevamente: tu madre no se llama Ana) y en definitiva, todos somosobjetos:
Eugenia, Jos y Ana y como objetos somos una clase de persona.
Entonces:

Una clase es un modelo para definir objetos que pueden realizar las mismas
acciones y poseen caractersticas similares.
En nuestro caso, crearemos decenas, miles y millones (ojal!) de presupuestos.Cada
uno de nuestros presupuestos, ser un objeto que se crear en base al modelo
ModeloDePresupuesto definido en la clase.

CLASES
Una clase se define mediante class NombreDeLaClase:

COMENTANDO CDIGO EN PYTHON


Mira las lneas que comienzan con el signo # (como esta):

# Datos comerciales

Todas las lneas comenzadas por # son comentarios en el cdigo fuente. Y aquellos
bloques de texto, encerrados entre tres comillas dobles como ste:

"""
Esta funcin se encarga de armar todo el presupuesto

"""

Tambin son comentarios, pero que adems, sirven para generar la documentacin de
un mtodo.

COMENTARIOS
Para comentar y documentar cdigo en Python utiliza:
# comentario o sino """ documentacin """

DEFINICIN DE VARIABLES EN PYTHON

# Datos comerciales
titulo = "PRESUPUESTO"
encabezado_nombre = "Eugenia Bahit"
encabezado_web = "www.eugeniabahit.com.ar"
encabezado_email = "mail@mail.com"
# Datos impositivos
alicuota_iva = 21

Las variables, en nuestro ModeloDePresupuesto, son las propiedades (o atributos)


caractersticos de nuestro presupuesto. Para definir una propiedad (atributo o variable)
se utiliza:

nombre_de_la_variable = dato

VARIABLES

Las variables en Python se definen mediante nombre_variable = dato

El nombre de una variable puede empezar (y continuar) por: Maysculas, minsculas,


guiones bajos y tambin contener nmeros.
Algunos ejemplos:

variable
_otra_variable_
variable_con_numero_25
VARIABLE_CON_MAYUSCULAS
Variable_Mixta

TIPOS DE DATOS
Las variables pueden contener datos de diversos tipos, por ejemplo:
Cadenas de texto

nombre_de_la_variable = "Las cadenas de texto van entre comillas"

Nmeros enteros y nmeros flotantes

numero_entero = 100
numero_flotante = 1298.95

Datos booleanos (verdadero o falso)

variable_con_dato_verdadero = True
variable_con_dato_falso = False

REPITIENDO CADENAS DE TEXTO

# Propiedades relativas al formato


divline ="="*80

Utilizando el asterisco * seguido de un nmero, estamos indicando la cantidad de veces


que repetiremos la cadena de texto colocada entre comillas:

variable_1 = "a"*3

es igual que:

variable_1 = "aaa"

Si has llegado hasta ac sin problemas, eso quiere decir que has cumplido con el primer
paso para aceptar el reto de aprender Python programando. No te pierdas el segundo
captulo.

APRENDIENDO A PROGRAMAR EN PYTHON EN 20 MINUTOS


https://www.youtube.com/watch?v=wp4DgNbGAUI

Como complemento a esta gua, te recomendamos el vdeo de Mejorando.la junto con


Arturo Jamaica aprendemos en 20 minutos a programar algo bsico en Python. Te
recomiendo que vayas al minuto 37 directamente para ir a lo importante del vdeo.

MTODOS Y PROPIEDADES EN PYTHON

En este segundo captulo, seguimos con nuestro


ejemplo presupuesto.pyintroducindonos a desarrollar, los temas pendientes
del captulo I, pero no sin antes, unos consejos para razonar errores de cdigo
como un programador profesional:
1. No desesperes. La magia en la programacin no existe. Si el cdigo falla, es porque algo
hemos hecho mal.
2. Lee detenidamente el error que Python devuelve (presta atencin a las ltimas lneas
donde se detalla lnea en la que falla, mtodo o algoritmo donde se produce y
descripcin del error). Un ejemplo:

3. Traceback (most recent call last):


4.

File "", line 1, in

5.

File "presupuesto.py", line 158, in

6.

presupuesto = ModeloDePresupuesto()

7.

File "presupuesto.py", line 152, in __init__

8.

self.set_datos_basicos()

9.

File "presupuesto.py", line 45, in set_datos_basicos

10.
11.
12.
13.

self.seleccionar_plan()
File "presupuesto.py", line 59, in seleccionar_plan
elegir_plan = int(elegir_plan)
ValueError: invalid literal for int() with base 10: ''

>>>

14.

Intenta resolverlo tu mismo cmo?


1. lee la descripcin del error y piensa como se produjo (es decir, cul fue el paso
previo)
2. verifica la lnea de cdigo donde se produjo el error sintaxis?
3. Compara el cdigo con el del ejemplo. Lo ves igual? Entonces no pierdes nada,
copindolo textualmente de nuevo.
4. Sigue fallando? busca el error en Internet (Google?)
15.Si no logras resolverlo, busca ayuda: aqu, en foros o listas de correo, PERO, previamente
ten en cuenta:

1. Copia el error completo, tal cual se muestra y colcalo como referencia en tu post
2. Copia tu cdigo en algn sitio que te permita compartir y corregir cdigo
pblicamente, como por ejemplohttp://pastebin.lugmen.org.ar/
3. Coloca en tu post, un enlace hacia el cdigo del Pastebin

Pero por qu tanto lo si es ms sencillo preguntar y listo?. Creme: no lo es.


Podr ser simple preguntar sin intentar resolverlo, pero ser complejo cuando comiences
a leer las posibles soluciones, pues pueden no estar basadas en la verdadera causa
(nadie est all para conocer tu cdigo ni como se produjo el error). Y por otro lado, si no
intentas resolverlo tu mismo, te ser ms difcil aprender.
Ahora s, retomemos nuestro cdigo!

DEFINICIN DE FUNCIONES EN PYTHON


def set_cliente(self):

Una funcin (o mtodo) es la forma de definir una determinada accin que


realiza un objeto.

DEFINIR FUNCIONES
Para definir una funcin, se escribe:

def nombre_de_la_funcion(parmetros):
# aqu escribimos el cdigo que realiza la accin que definimos

Los parmetros son datos contenidos en variables (una o ms), que la funcin
necesitar para realizar la accin. No siempre son necesarios. En nuestro caso, el
parmetro self indica que la funcin requerir de los atributos contenidos en la clase (los
que ya vimos recientemente).
Por ejemplo: self.empresa est llamando al atributo empresa de la clase.
Mientras que mediante: self.empresa = 'Maestros del Web', le estoyasignando el valor
Maestros del Web al atributo empresa de la clase (recuerda que un atributo es una
variable).

REFERENCIA A PROPIEDADES
Cuando necesito recurrir a un atributo de la clase, dentro de una funcin,
escriboself.nombre_del_atributo

Todo el cdigo contenido dentro de una funcin (es decir, el que est debajo de la
definicin de la funcin, con tabulado), se llama algoritmo, y es el que indicar a la
funcin, qu es lo que debe hacer.

INTERACTUANDO CON EL USUARIO MEDIANTE


RAW_INPUT
def set_cliente(self):
self.empresa = raw_input('\tEmpresa: ')
self.cliente = raw_input('\tNombre del cliente: ')

es una funcin. Pero no la definimos nosotros, sino que es una funcin


nativa de Python.
raw_input()

La accin que realiza raw_input('Texto que le mostrar al usuario'), es:


1. Muestra al usuario el texto que se encuentra entre comillas, dentro de los parntesis (es
decir, que este texto es un parmetro requerido por la funcin)
2. Espera que el usuario escriba algo
3. Luego, almacena lo que el usuario escribi. En nuestro caso, ser almacenado en los
atributos de la clase, empresa y cliente.

FLOAT() OTRA FUNCIN NATIVA (PROPIA) DE PYTHON

importe = raw_input('\tImporte bruto: $')


self.importe = float(importe)

Hemos almacenado en la variable importe un dato ingresado por el usuario:

importe = raw_input('\tImporte bruto: $')

Luego, asignamos esa variable (importe) como valor del atributo importe, pero esta vez,
es el atributo importe de la clase:

self.importe = float(importe)

FUNCIONES NATIVAS
al igual que raw_input() es una funcin nativa de Python. Su accin consiste en
convertir en nmero flotante (es decir, con decimales), el nmero que le sea pasado
como parmetro.
Float()

OPERADORES MATEMTICOS: SUMAR, RESTAR, DIVIDIR Y


MULTIPLICAR CON PYTHON
self.monto_iva = self.importe*self.alicuota_iva/100
self.neto = self.importe+self.monto_iva

Podemos realizar sumas, restas, multiplicaciones y divisiones con Python. Y podemos


almacenar los resultados de nuestras operaciones matemticas en variables, incluso
aquellas que sean atributos de la clase.
Podemos realizar operaciones matemticas con nmeros: 1+1 y tambin con variables
cuyos valores sean nmeros: variable_1+variable_2

OPERADORES MATEMTICOS

Para
Para
Para
Para
Para
Para
Para

sumar, utilizamos +
restar utilizamos dividir flotantes utilizamos /
dividir enteros utilizamos //
multiplicar utilizamos *
obtener el resto de una divisin utilizamos %
exponenciar utilizamos **

EL OPERADOR MATEMTICO SUMA (+)


txt = '\n'+self.divline+'\n'
txt += '\t'+self.encabezado_nombre+'\n'

El operador matemtico + no solo sirve para sumar nmeros. Tambin sirve para
concatenar cadenas de texto (es decir, unirlas). Fjate esta lnea:

txt = '\n'+self.divline+'\n'

Estoy diciendo que la variable txt es igual a:


la cadena de texto \n (\n significa salto de lnea)
ms el texto contenido en el atributo divline de la clase
ms nuevamente, una cadena de texto \n
Luego, mira la lnea que le sigue:

txt += '\t'+self.encabezado_nombre+'\n'

Estoy diciendo aqu, que a la variable txt de antes, le agregue ahora, todo lo dems:
La cadena de texto \t (\t significa tabular)
el texto contenido en el atributo encabezado_nombre de la clase
ms finalmente, la cadena de salto de lnea \n

DANDO FORMATO A CADENAS DE TEXTO

txt += '\tImporte: $%0.2f | IVA: $%0.2f\n' % (self.importe,


self.monto_iva)

Haz visto lo difcil de entender que parece este cdigo? Pues Pirdele el miedo! Es
mucho ms sencillo de lo que parece.
Python nos da la posibilidad de utilizar comodines en nuestras cadenas de texto, para
poder reemplezar datos, que necesiten un formato especial.
El comodn es el signo del porcentaje %.
A este comodn, le segurir un patrn, que identifique el tipo de dato (formato) que
queremos darle al dato.
Por ejemplo: %0.2f, est indicando que en ese lugar (en vez del comodn y el patrn),
debe ir un nmero flotante con dos decimales. Es decir que el
patrn 0.2fsignifica nmero con dos decimales.
Hasta all, entonces, asignamos comodines y patrones. Pero luego, hay que decirle a
Python qu datos debe formatear. Para ello, luego de la cadena de texto, escribimos
un comodn % segudio de un espacio, y entre parantsis y separados por coma,
las variables que contienen los datos a reemplazar.
Vemoslo con otro ejemplo:

a = 10
b=5
resultado = "%0.2f y %0.2f son dos nmeros flotantes" % (a, b)

Eso, sera como haber escrito esto:

resultado = "10.00 y 5.00 son dos nmeros flotantes"

IMPRIMIENDO TEXTO EN LA PANTALLA

print txt

Cuando quieres mostrar texto en la pantalla, solo debes escribir print y lo que desees
mostrar.
Pueden ser tanto los datos contenidos en una variable (como en nuestro cdigo) o
directamente un dato, como en los siguientes ejemplos:

print 25
print "Cadena de texto"

CREACIN DE OBJETOS
# Instanciar clase
presupuesto = ModeloDePresupuesto()

Recuerdas cuando hablamos de la diferencia entre clases y objetos? Decamos que una
clase es un modelo que sirve como base para crear un objeto.
Pues bien. Es hora de crear nuestro nuevo objeto: un nuevo presupuesto.

CREAR OBJETOS
Para instanciar una clase y crear un nuevo objeto se escribe:

nombre_del_objeto = NombreDeLaClase()

Con lo anterior, hemos iniciado un nuevo objeto que ser creado segn el modelo
NombreDeLaClase.

MTODO CONSTRUCTOR DE LA CLASE: __INIT__


# Mtodo constructor
def __init__(self):

def __init__(self):

es la definicin de una funcin, al igual que todas las anteriores lo

notas?
Pero el nombre de la funcin __init__, Python lo reserva para los mtodos constructores.

Un mtodo constructor de una clase, es una funcin que se ejecuta


automticamente cuando crea un objeto.
Estos mtodos son sumamente tiles, cuando (como en nuestro caso), necesitamos
automatizar todas las tareas.
Anteriormente, vimos como crear el objeto. Si no hubisemos generado un mtodo
__init__, lo que vimos al comienzo cuando ejecutamos presupuesto.py en la consola, no
hubiese sido posible, ya que tendramos que haberle dicho manualmente a nuestro
objeto, que realice cada una de las acciones, por ejemplo:
presupuesto.set_cliente() para que realice la accin de crear los datos del cliente
presupuesto.calcular_iva() para que calculara el importe de IVA
Y as con cada accin definida en la clase.
Pero, el mtodo __init__ nos facilita la vida. Pues all dentro, os encargamos de llamar a
todas las funciones (acciones) en el orden correcto, ahorrndonos mucho tiempo:

def __init__(self):
# en las siguientes lneas, imprimo texto en pantalla
print self.divline
print "\tGENERACIN DEL PRESUPUESTO"

print self.divline
self.set_cliente() # aqu seteo los datos del cliente
self.set_datos_basicos() # aqu los del presupuesto
self.calcular_iva() # calculo el iva
self.calcular_neto() # calculo el importe total
self.armar_presupuesto()

Finalmente, llam a la funcin que se encarga de convertir a texto todo el presupuesto.

LLAMAR FUNCIN DENTRO DE OTRA


Para llamar a una funcin y que sta, se ejecute en el interior de otra, se
utilizaself.nombre_de_la_funcion()

CHULETA DE LOS CAPTULOS I Y II

NUEVO DESAFO
En el captulo de hoy, nos extendimos en cuestiones tericas sobre referencias del
lenguaje que utilizamos en nuestro primer ejemplo. Aprendimos muchas cosas nuevas
como:

Definir funciones
Utilizar funciones nativas de Python

Operadores matemticos
Dar formato a cadenas de texto
Entre otras

Pero algo muy importante que aprendimos es a perderle el miedo a los errores de
cdigo y tratar de resolverlos. Y si quieres convertirte en verdadero profesional,
te invito a sumarte a un nuevo desafo. A continuacin, encontrars un cdigo fuente.
Este cdigo, utiliza algunas cosas que ya hemos aprendido. Adems, no te dir donde,
pero tiene algn que otro error.

EL RETO DE HOY
1. Copia el siguiente cdigo en un archivo, con el nombre que se te ocurra
2. Ejectalo en una terminal (ya sabes como)
3. Ve si puedes encontrar el (o los) error(es) y corregirlo(s)
4. Si encuentras el(los) error(es), NO lo postees as das tiempo a los dems a hacer lo
mismo. Pero, puedes contar que los encontraste y dar pistas para ayudar a otros.
5. Si NO encuentras los errores, puedes postear preguntando a quienes s los hayan
encontrado

Si aprendes a trabajar en equipo, colaborando con tus pares (ya sea


ofreciendo o pidiendo ayuda) y evitando la competencia, estars listo para
afrontar verdaderos desafos laborales, que harn que tu carrera se
destaque.

AQU, EL CDIGO FUENTE

# -*- coding: utf-8 -*class Modelo:


def __init__(self):
self.divisor = 23
valor = raw_input("Elige un nmero entero entre 0 y 100: ");
resultado = self.devolver_resultado(valor)
print "%d/%d es %d" % (valor, self.divisor, resulatdo)
def devolver_resultado(self, numero):
"""Divide el nemro por el divisor y devuelve un entero"""

resultado = numero//self.divisor
return resultado

obj = Modelo()

LISTAS, TUPLAS, DICCIONARIOS Y ESTRUCTURAS DE CONTROL


ACTUALIZADO:
Sobre error en la llamada a self.leer_plantilla()

Debe eliminarse el primer self de la llamada:

txt = self.leer_plantilla(self.txt)
html = self.leer_plantilla(self.html)

Muy buenas Pythoneros! estamos aqu con la tercera entrega de Aprender Python
Programando.
El desafo de hoy, no es apto para personas impresionables, pues Bienvenid@s a
un nuevo reto para corajud@s!
Qu haremos? Hoy agregaremos ms funcionalidad a nuestro mdulo Presupuesto.
1. Disearemos una plantilla HTML y otra plantilla TXT para nuestro presupuesto, as,
no solo se ver ms agradable, sino que adems, ser ms fcil modificarlo
2. Comenzaremos a colocar una numeracin incremental automtica, a cada nuevo
presupuesto que generemos
3. Podremos elegir entre guardar el archivo en formato HTML o mostrarlo en pantalla
4. Crearemos una lista de precios Basta de agregar tantos datos manualmente!

Finalmente, nuestro programa se ver as:

Produciendo presupuestos en formato HTML, como el siguiente:

CMO FUNCIONAR AHORA?


Ahora, solo nos pedir:
1. Los datos de la empresa y la fecha del presupuesto (igual que antes)
2. En vez de detallar el servicio y el importe, los obtendr de una lista de precios, por lo cual,
solo nos pedir ingresar el cdigo correspondiente al plan:
0: Plan corporativo
1: Plan personal
2: Plan de mantenimiento
3. Calcular automticamente el nmero de presupuesto, y
4. Finalmente nos preguntar si deseamos guardar el archivo:
1. Si elegimos S (si), guardar un HTML y nos informar el nombre del archivo (que
ser el nmero de presupuesto con extensin .html)
2. Si elegimos N (no), nos mostrar el presupuesto en pantalla como lo haca hasta
ahora
3. Si nos equivocamos, y no elegimos ni S (si) ni N (no), nos avisar que
ingresamos una opcin incorrecta, y nos dar la oportunidad, de volver a elegir.

Comencemos!

ARCHIVOS NECESARIOS
Para hacerte de los archivos necesarios, sigue los temes de esta lista, paso por paso:
1. Crea una carpeta llamada capitulo3
Aqu almacenaremos todos los archivos del programa
2. Dentro de la carpeta capitulo3, crea una subcarpeta llamadapresupuestos
Aqu se guardarn todos los presupuestos generamos en formato HTML (los que
decidamos guardar)
3. Dentro de la carpeta capitulo3, crea otra subcarpeta llamada templates
Aqu guardaremos la plantilla HTML y otra con formato solo texto (TXT)
4. Dentro de la carpeta templates guarda los archivos template.html ytemplate.txt
Pulsa en cada archivo para descargarlos desde Launchpad. Estas sern, nuestras dos
plantillas
5. Dentro de la carpeta capitulo3, crea un archivo llamado contador.txt
Ser la gua que utilizaremos para calcular incrementalmente nuestros nmeros de
presupuesto.
6. Abre el archivo contador.txt, edita el contenido (est vaco), escribe 100 y guarda los
cambios
Inicializamos el contador en 100. Nuestro primer presupuesto, obtendr el nmero 101 y
as sucesivamente de forma incremental.
7. Dentro de la carpeta capitulo3, guarda el mdulo presupuesto.py(modificado)
Explicaremos todos los cambios nuestro mdulo, a lo largo del captulo.

Finalmente, la estructura de archivos y directorios, deber verse as:

[-]capitulo3
|_ [+]presupuestos
|_ [-]templates
|_ template.html
|_ template.txt
|_ contador.txt
|_ presupuesto.py

LA LISTA DE PRECIOS: LISTAS, TUPLAS Y DICCIONARIOS


Te voy a pedir que abras el mdulo Presupuesto (presupuesto.py) y vayas a lalnea 22:

# Planes y servicios - Captulo 3


planes = ('corporativo', 'personal', 'mantenimiento')

# Tupla

corporativo = ['Diseo Sitio Web corporativo', 7200]

# Lista

personal = ['Diseo Sitio Web bsico', 4500]

# Lista

mantenimiento = ['Mantenimiento sitio Web (mensual)', 500] # Lista


lista_precios = {'corporativo':corporativo,
'personal':personal,
'mantenimiento':mantenimiento}

# Diccionario

Como vers, hemos agregado cuatro nuevas propiedades de clase a nuestro mdulo.
Pero, el tipo de datos, no es ninguno de los que ya hemos visto! Pertenecen a tres
nuevos tipos de datos: tuplas, listas y diccionarios.
Tanto las tuplas, como listas y diccionarios, son una forma de almacenar varios datos
diferentes, de diversos tipos (cadenas de texto, enteros, flotantes, booleanos) en
una misma variable.
El orden en el cual estos datos se especifican dentro de la variable, se denomina
ndice, teniendo el primer dato un ndice 0 (cero), el siguiente 1, y as
incrementalmente.
Veamos estos tres nuevos tipos de datos en detalle:

TUPLAS

planes = ('corporativo', 'personal', 'mantenimiento')

El contenido de una tupla se escribe siempre entre parntesis ( )


Admite cualquier tipo de dato:
mi_tupla = (texto, 100, 7.25, False, True)

Para acceder a uno de esos datos, se realiza por su nmero de ndice: texto es ndice 0;
100 es ndice 1; 7.25 es ndice 2; False es ndice 3 y,True es ndice 4
Para acceder a una variable por su nmero de ndice, ste se escribe entre corchetes: print
mi_tupla[2] imprimir 7.25 mientras que print mi_tupla[4] imprimir True

Los datos contenidos en una tupla no pueden modificarse.

En nuestro cdigo, la tupla planes lo que est haciendo es almacenar el nombre de los
tres tipos de planes que ofreceremos a nuestros clientes.

LISTAS

corporativo = ['Diseo Sitio Web corporativo', 7200]


personal = ['Diseo Sitio Web bsico', 4500]
mantenimiento = ['Mantenimiento sitio Web (mensual)', 500]

El contenido de una lista se escribe siempre entre corchetes [ ]

Admite cualquier tipo de dato:


mi_lista = ['texto', 100, 7.25, False, True]

Para acceder a uno de esos datos, se realiza por su nmero de ndice al igual que con las
tuplas: print mi_lista[2] imprimir 7.25 mientras que print mi_lista[4] imprimir True

A diferencia de las tuplas, los datos contenidos en una lista PUEDEN modificarse,
accediendo a ellos por su nmero de ndice:
mi_lista[0] = 'otro contenido'

En nuestro cdigo, hemos creado una lista para cada tipo de plan, donde el ndice 0
(cero) ser la descripcin del servicio y el ndice 1, el precio de ese servicio.

DICCIONARIOS

lista_precios = {'corporativo':corporativo,

'personal':personal,
'mantenimiento':mantenimiento}

El contenido de un diccionario se escribe siempre entre llaves { }

Admite cualquier tipo de dato


Cada dato almacenado en un diccionario, debe llevar un nombre de claveantecediendo
al dato:

diccionario = {'nombre_de_clave':'texto',

'numero_entero':100,

'numero_flotante':7.25,

'falso':False,

'verdadero':True}

Para acceder a uno de esos datos, se realiza por su nombre de clave:


print diccionario['numero_entero'] imprimir 100 y si deseo modificar 100 por 125, escribo:

diccionario['numero_entero'] = 125. Es decir que al igual que las listas, se pueden


modificar los datos.

En nuestro cdigo, hemos creado un diccionario para englobar el nombre de nuestros


planes (que actuar como nombre de clave) y el valor de cada clave, ser cada una de
nuestras listas.

PARA SABER
Las tuplas, listas y diccionarios, admiten tambin como valores, otras tuplas, listas y/o
diccionarios!

tupla1 = ('rosa', 'verde', 'rojo')


tupla2 = (tupla1, 'celeste')
tupla3 = ('hortensia', 'neomarica', 'rosa', 'jazmin')

lista1 = [tupla1, tupla2, 'negro', 'amarillo']


lista2 = [lista1, 'naranja']

diccionario1 = {'colores':lista2, 'plantas':tupla3}

gran_tupla = (diccionario1, 'y algo ms!')

Hasta aqu vemos como acceder uno a uno a los datos de una tupla, lista o diccionario.
Pero qu sucede si queremos recorrerlos todos y no sabemos cuantos ndices tiene?
Para ello, utilizaremos una estructura de control llamada bucle for.

Una estructura de control es un bloque de cdigo que permite tomar


decisiones de manera dinmica, sobre cdigo existente.

EL BUCLE FOR
En nuestro cdigo, la estructura de control que estamos implementado se
denomina bucle for y es la que se encuentra representada por el siguiente bloque de
cdigo (lneas 44, 45 y 46):

for plan in self.planes:


texto_a_mostrar += '(%d)%s ' % (codigo_plan, plan)
codigo_plan = codigo_plan+1

Por qu bucle? Porque es una accin que no se ejecuta solo una vez, sino que lo har
hasta que una condicin deje de cumplirse.
Qu condicin? la que restringe la ejecucin de ese bucle. En nuestro caso, la
condicin estar delimitada por la cantidad de planes en nuestra tupla planes: for plan in
self.planes:

Lo anterior puede leerse as:


[for] por
[plan] cada plan
[in] en self.planes
[:] hacer lo que sigue

Es decir que el condicionamiento (limitacin) est dado por la cantidad de


planes contenidos en la propiedad de clase, planes.
Luego, en cada iteracin (es decir, cada repeticin dentro del bucle) voy agregando
texto a la variable texto_a_mostrar utilizando una cadena con comodines los recuerdas?
Utilizo el patrn d que indica que all ir un dgito y el patrn s indicando que lo
reemplazar por una string, tal cual lo vimos en captulos anteriores:

texto_a_mostrar += '(%d)%s ' % (codigo_plan, plan)

Ese texto_a_mostrar es el que se utiliza luego en el raw_input() para preguntar qu


tipo de plan ofrecer.
Pero el cdigo de plan lo genero dinmicamente Cmo? Antes del bucle for, inicializo la
variable codigo_plan en cero:
codigo_plan = 0

En el bucle for, la voy incrementando en 1, con cada iteracin:


codigo_plan = codigo_plan+1

Qu obtengo? El ndice de cada plan dentro de la tupla:


ndice 0: corporativo
ndice 1: personal
ndice 2: mantenimiento
Y de dnde surge la variable plan? se declara automticamente en el bucle for:
for plan in self.planes:

CONVIRTIENDO A ENTEROS CON INT()


Siguiendo con el mtodo anterior, destinado a la seleccin de planes, pido ingresar el
cdigo correspondiente al plan, que a la vez ser el nmero de ndice del plan, dentro de
la tupla planes:

elegir_plan = raw_input(texto_a_mostrar)

raw_input() retorna el valor ingresado, como cadena de texto. Pero necesito utilizarlo
como nmero de ndice! entonces, convierto ese valor a entero, con otra funcin nativa
de Python: int()

elegir_plan = int(elegir_plan)

ACCEDIENDO A DATOS POR SU NMERO DE NDICE


Cuando ingresamos el cdigo de plan (0, 1 2) estamos ingresando un nmero de
ndice. Mediante:

self.plan = self.planes[elegir_plan]

Lo que estoy haciendo, es traer el nombre (valor) del tipo de plan almacenado en la
tupla planes.
Los datos del servicio a cotizar como descripcin y precio, los he guardado en el
diccionario lista_precios. Recordemos que al diccionario se accede por nombre de clave.
ste, lo obtuve antes haciendo self.planes[elegir_plan].
Entonces, accedo al diccionario para traerme la lista, que contiene descripcin del
servicio e importe, utilizando como clave, el nombre del plan:

datos_servicio = self.lista_precios[self.planes[elegir_plan]]

Almaceno la lista correspondiente al plan en una ueva variable


llamadadatos_Servicios.Pero esta variable, es una lista. Entonces, para obtener el
servicio, debo recurrir al ndice 0:

self.servicio = datos_servicio[0]

Y para obtener el importe, al ndice 1:

importe = datos_servicio[1]

Finalmente, formateo el importe con float():

self.importe = float(importe)

CHULETA #1
Con nuestra lista de precios hemos aprendido sobre:
Tuplas
Crear

mi_tupla = ('texto', 100, 25.83, False)

Acceder

print mi_tupla[1] # Imprime: 100

Modificar

No se puede!

Listas
Crear

mi_lista = ['texto', 100, 25.83, False]

Acceder

print mi_lista[2] # Imprime: 25.83

Modificar

mi_lista[0] = 'Otro valor'

Diccionarios:

Crear

dict = {'clave':'dato', 'otra_clave':155}

Acceder

print dict['otra_clave'] # Imprime: 155

Modificar

dict['clave'] = 'Texto'

Recorrer listas, tuplas y diccionarios con bucle for


flores = ['rosa', 'jazmn', 'crisantemo']
for flor in flores:
print 'Flor de ' + flor

Imprimir:
Flor de rosa
Flor de jazmn
Flor de crisantemo
Convertir un literal a entero:
literal = '234'
int(literal)

En el siguiente captulo veremos como logramos utilizar plantillas HTML para


nuestros presupuesto y como fue el proceso para almacenarlos. Ahora, un desafo
extra...

NUEVO RETO
Mirando el mtodo que se encuentra en la lnea 72 de nuestro mdulo Presupuesto:

# Armar numero de presupuesto


def armar_numero_presupuesto(self):
contador = open('contador.txt', 'r+') # Abro contador
ultimo_num = int(contador.read())
nuevo = ultimo_num+1
contador.seek(0)
nuevo = str(nuevo)

# obtengo ultimo numero


# genero nuevo nmero

# muevo cursor a byte 0


# convierto numero a string

contador.write(nuevo)
contador.close()

# sobreescribo el nmero
# cierro contador

self.numero_presupuesto = nuevo

# seteo el nuevo nmero

Leyendo los comentarios a la derecha de cada lnea Alguien se anima a explicar por
qu luego de abrir un archivo, leerlo y antes de escribirlo se
utilizacontador.seek(0) para "mover el cursor al byte 0"?
Vamos a ver esto de forma detallada en el siguiente captulo, pero quin se anima a
tratar de deducirlo y explircarlo?
TRABAJANDO CON TEMPLATES, ARCHIVOS Y CONDICIONALES

En el captulo anterior, estuvimos modificando nuestro programa: creamos una lista de


precios y agregamos plantillas HTML y TXT para imprimir los presupuestos.
Vimos como utilizar tuplas, listas y diccionarios e incorporamos una nuevaestructura
de control mediante el bucle for en el proceso de creacin y utilizacin de listas de
precios para nuestro programa.

En el captulo de hoy, veremos cmo logramos utilizar plantillas para generar


nuestros presupuestos y el proceso para guardarlos.
Comenzaremos con algo sencillo y sumamente prctico: lectura y escritura de
archivos.

LECTURA Y ESCRITURA DE ARCHIVOS


Al trabajar con archivos, existen cuatro acciones bsicas que podemos hacer con un
archivo:

Abrir un archivo
Leer un archivo
Escribir/sobrescribir un archivo
Cerrar un archivo abierto

Cuando abrimos un archivo podemos hacerlo con diversos fines:

Abrirlo para leerlo


Abrirlo para escribirlo
Abrirlo para leerlo y escribirlo, etc

Para abrir un archivo se realiza mediante la clase open() de Python, cuyo mtodo
constructor recibir como primer parmetro, la ruta del archivo a ser abierto y
como segundo parmetro, el modo de apertura (es decir, el objetivo para el cual lo
abrimos: escritura, solo lectura, lectura y escritura, etc.).
En la lnea 103 abrimos un archivo para leerlo:

filename = open(archivo, 'r')

Donde archivo es la ruta del archivo pasada como parmetro en el mtodo


leer_plantilla() y la cadena r representa el modo de apertura solo lectura.
Mientras tanto, en la lnea 74, abrimos un archivo no solo para leerlo, sino tambin para
escribirlo:

contador = open('contador.txt', 'r+')

En este caso, r+ significa lectura y escritura.


Sin embargo, en la lnea 92, estamos abriendo un archivo, pero para crearlo. Utilizando
en este caso el modo w, que crear el archivo si no existe (o lo reemplazar si existe,
creando uno nuevo con el mismo nombre), preparndolo para ser escrito:

presupuesto = open(filename, 'w')

Tanto con la variable filename como con la variable contador y presupuesto, lo que
estamos haciendo es crear un objeto archivo, para luego utilizar los mtodos
necesarios:
para leer el contenido de un archivo;
objeto.write('nuevo contenido') para escribir en el archivo;
objeto.seek(numero_de_byte) para mover el cursor hacia el byte indicado en el archivo;
y objeto.close() para cerrar el archivo.
objeto.read()

Cuando leemos el contenido de un archivo con el mtodo read(), ste, retorna una
cadena de texto. Si el contenido del archivo que estamos leyendo, es un nmero
(como en nuestro contador.txt), obtendremos el literal de ese nmero y para poder

utilizarlo como nmero (por ejemplo, para hacer operaciones matemticas), ser
necesario convertirlo a entero o flotante, como en la lnea 75, donde
medianteint() convertimos el literal ledo a nmero entero:

ultimo_num = int(contador.read())

APRENDIENDO A UTILIZAR TEMPLATES EN PYTHON


IMPORTACIN DE MDULOS

presupuesto.py es nuestro mdulo.


Cualquier otro archivo con extensin .py, tambin es un mdulo.
Python, tiene sus propios mdulos.
Cualquier mdulo Python (propio o provisto por Python) puede ser importado.

IMPORTAR MDULOS
Importar un mdulo significa incluir un archivo .py dentro de otro, para utilizar sus
mtodos.
Para importar todo un mdulo, se escribe:
import modulo

Para importar solo una clase de un mdulo, se escribe:


from modulo import Clase

Para importar varias clases de un mdulo, se separan los nombres de las clases con
comas:
form modulo import ClaseUno, ClaseDos, ClaseVeinte

En nuestro ejemplo:

form string import Template

Estamos importando la clase Template del mdulo string de Python.


Esta clase, es la que nos va a permitir utilizar una plantilla para nuestro presupuesto y
luego hacer un render (reemplazo dinmico) de datos.

XKCD This work is licensed under a Creative Commons Attribution-NonCommercial 2.5 license.

LA CLASE TEMPLATE DEL MDULO STRING DE PYTHON


Mira la lneaa 131 y 132 del mdulo presupuesto.py:

txt = Template(txt).safe_substitute(diccionario)
html = Template(html).safe_substitute(diccionario)

Template() es una clase del mdulo string de Python.

El constructor de esta clase (es decir, el mtodo __init__) recibe como parmetro una
plantilla: Template(txt) y Template(html)

Esta plantilla, debe tener ciertos comodines que indicarn los datos que deben ser
reemplazados.
Estos comodines se denominan identificadores.

Los identificadores, se escriben con un signo $ delante:$nombre_del_identificador. Estos


identificadores los hemos colocado en nuestro archivo template.txt y tambin
en template.html

Para escribir un signo $ sin hacer referencia a un identificador, debe escaparse con otro
signo $. Esto: $$ imprime $, mientras que$nombre_identificador ser reemplazado por
un identificador cuyo nombre sea nombre_identificador

Los mtodos substitute() y safe_substitute() de la clase Template

Como nuestra clase Presupuesto, Template, tiene sus propios


mtodos:substitute() y safe_substitute()
Ambos mtodos, reciben como parmetros, un diccionario de datos.
Este diccionario se compone de clave=valor donde clave, ser el nombre de
un identificador y valor, el dato por el cul ser reemplazada la clave.

UN EJEMPLO SIMPLE

from string import Template


print Template('Reemplazar $identificador').substitute(identificador='valor de reemplazo')

La salida de lo anterior, ser:


Reemplazar valor de reemplazo

MTODOS DE LA CLASE TEMPLATE


La diferencia entre el mtodo substitute() y safe_substitute(), es que si nos
olvidamos de colocar el valor para un identificador, el primer mtodo generar un error,
mientras que el segundo, simplemente lo dejar sin reemplazar.

Es decir que si escribimos

Template('Este es el $id1 y este $id2).safe_substitute(id1='Identificador Uno')

La salida ser:
Este es el Identificador Uno y este $id2

Mientras que substitute provocara un error.

DICT(): CREACIN DE DICCIONARIO DE DATOS


Ve a al lnea 116 del mdulo presupuesto:

diccionario = dict(nombre=self.encabezado_nombre,
web=self.encabezado_web,
email=self.encabezado_email,
titulo=self.titulo,
numero=self.numero_presupuesto,
fecha=self.fecha,
empresa=self.empresa,
cliente=self.cliente,
plan=self.plan,
servicio=self.servicio,
precio=self.importe,
iva=self.monto_iva,
total=self.neto,
limite=self.vencimiento)

Aqu lo que hicimos, fue armar un diccionario de datos con la clase dict() de Python.
Podramos haber colocado estos pares de clave=valor dentro del
mtodosafe_substitute() directamente. Pero para hacerlo ms legible y prolijo, creamos
este diccionario de datos, que luego lo pasamos como parmetro a safe_substitute():

txt = Template(txt).safe_substitute(diccionario)
html = Template(html).safe_substitute(diccionario)

CHULETA PARA UTILIZAR TEMPLATES


Para utilizar una plantilla, debemos:
1. Crear la plantilla en un archivo, colocando identificadores antecedidos por el
signo $ en los lugares donde necesitemos reemplazar los datos dinmicamente.
2. Importar la clase Template del mdulo string de Python:
from string import Template

3. Guardar el contenido de la plantilla en una variable:

4. # Crear un objeto archivo: Abrir el archivo en modo de solo lectura


5. archivo = open('archivo', 'r')
6. # Leer el archivo
7. contenido = archivo.read()
8. # No olvidarse de cerrar el archivo
9. archivo.close()

10.Crear un diccionario de datos con dict():


diccionario = dict(id='un valor', otro_id='Otro valor')

11.Hacer un render de datos con la clase Template y el


mtodo substitute()o safe_substitute() (este ltimo, es mejor para prevenir errores):
Template(plantilla).safe_substitute(diccionario)

Dnde plantilla debe ser el contenido del archivo ledo previamente ydiccionario el
creado mediante la clase dict()

CHULETA DE OPERACIONES BSICAS CON ARCHIVOS

ESTRUCTURAS DE CONTROL EN PYTHO: IF ELIF Y


ELSE
Guardamos el presupuesto, lo imprimimos en pantalla, o? En el captulo
anterior estuvimos hablando sobre estructuras de control con el bucle for. Hoy,
incorporamos una nueva estructura de control: el condicional if:

if respuesta.lower() == 'n':
print txt
# si en cambio el usuario indica "n"
elif respuesta.lower() == 's':
filename = 'presupuestos/'+self.numero_presupuesto+'.html'
presupuesto = open(filename, 'w') # Creo el archivo

presupuesto.write(html)
presupuesto.close()

# escribo el contenido
# cierro el archivo

print '\n\tEl archivo se ha guardado en '+filename+'\n\n'


# sino
else:
print '\n\tOpcin incorrecta. No se guard el presupuesto.\n\n'
self.guardar_presupuesto(txt, html)

(ver lneas 87 a 99)


El condicional if, elif y else, es uno de los que ms utilizars en tu vida como
programador. Bsicamente, al igual que otras estructuras de control, permite tomar
decisiones si una determinada condicin se cumple. El razonamiento de
condicionales puede representarse como sigue:

si condicion X se cumple:
hacer esto
sino, si condicion Y se cumple:
hacer esto otro
sino (si no se cumple ni X ni Y):
hacer tal otra cosa

No necesariamente el condicional debe cumplir esa estructura. A veces solo es necesario


evaluar una nica condicin y tomar una decisin SOLO sobre la base de si esta
condicin se cumple:

si condicin X se cumple:
hacer esto
# fin

Ejemplo:

a = 10
if a == 10:
print 'a es igual a 10'

O tambin, tomar una decisin si la condicin se cumple y otra si no se cumple:

a = 10
if a == 10:
print 'a es igual a 10'
else:
print 'a no es igual a 10'

Con elif se pueden tomar tantas decisiones como condiciones quieran evaluarse::

a = 10
if a == 10:
print 'a es igual a 10'
elif a == 9:
print 'a es igual a 9'
elif a == 75:
print 'a no es ni 9 ni 10, es 75'

Y si a lo anterior le agregamos else estaramos cubriendo todas las posibilidades:

a = 10
if a == 10:
print 'a es igual a 10'
elif a == 9:
print 'a es igual a 9'
elif a == 75:
print 'a no es ni 9 ni 10, es 75'
else:
print 'a no es ni 9, ni 10 ni 75. Es un valor que no evalu'

Retomemos nuestro cdigo. En el mtodo guardar_presupuesto() (lnea 84), lo primero


que hago es preguntar si se desea guardar o no el presupuesto, siendo las respuestas
esperadas s (s, lo deseo guardar) o n (no, no deseo guardarlo):

respuesta = raw_input('\n\tDesea guardar el presupuesto? (s/n): ')

Solo espero una de esas dos respuestas. Es necesario evaluar la respuesta ingresada.

if respuesta.lower() == 'n':

El mtodo lower() me convierte el valor ingresado por el usuario a minsculas, para


que me sea ms sencillo evaluar la condicin. Bsicamente la condicin que estoy
evaluando es: si la respuesta fue no.
Al evaluar una condicin, la estructura de control responder con True (verdadero) o
False (falso). Si la respuesta ingresada fue n, entonces la condicin cumple.
Sino, si la respuesta fue s elif respuesta.lower() == 's': se est cumpliendo esta condicin
(se eligi si).

Pero tambin puede suceder, que ni s ni n sean ingresados. sto, lo evalo


genericamente con else:
Razonando la estructura completa:
Si la respuesta es n, imprimo el presupuesto en pantalla

if respuesta.lower() == 'n':
print txt

En cambio, si la respuesta es s, creo un nuevo archivo y lo guardo.

elif respuesta.lower() == 's':


filename = 'presupuestos/'+self.numero_presupuesto+'.html'
presupuesto = open(filename, 'w')
presupuesto.write(html)
presupuesto.close()
print '\n\tEl archivo se ha guardado en '+filename+'\n\n'

Pero si la respuesta no es ni n ni s, vuelvo a ejecutar este mismo mtodo desde el


comienzo, es decir que el mtodo guardar_presupuesto() se llama a s mismo:

print '\n\tOpcin incorrecta. No se guard el presupuesto.\n\n'


self.guardar_presupuesto(txt, html)

RECURSIVIDAD
Cuando un mtodo se llama a s mismo, se denomina recursividad. sto, genera una
iteracin (un bucle) del mtodo en s mismo. Por lo tanto, se debe ser muy cuidadoso al

emplear una llamada recursiva y hacerlo solo cuando sea estrictamente necesario y
no se corra el riesgo de caer en un bucle infinito.

OPERADORES LGICOS Y RELACIONALES


Para evaluar condiciones no solo podemos recurrir a si X es igual a Y. Existen
otros operadores que nos permitirn evaluar diferentes condiciones. Estos operadores
se denominan operadores lgicos que nos permitirn evaluar mltiples condiciones en
un mismo proceso y operadores relacionales, que nos permitirn evaluar la relacin
existente en una condicin dada.

OPERADORES RELACIONALES

== Igual que
!= Distinto que
<

Menor que

>

Mayor que

>= Mayor o igual que


<= Menor o igual que

Usos:
if
if
if
if
if
if

a
a
a
a
a
a

== b # si a es igual que b
!= b # si a es distinto que b
> b # si a es mayor que b
>= b # si a es mayor o igual que b
< b # si a es menor que b
<= b # si a es menor o igual que b

OPERADORES LGICOS

and (y)
or

(o)

not (no)

Los operadores lgicos permitirn evaluar mltiples condiciones en una misma instancia:
si condicion_1 and condicion_2 or condicion_3
and evala si todas las condiciones se cumplen, es decir, que todas las condiciones
deben retornar True (verdadero)

a = 10
b=5
if (a == 10) and (b != 10):
print 'Hola Mundo'

Se lee: Si (a es igual que 10) y (b es distinto que 10)


Como ambas condiciones se cumplen se imprimir Hola Mundo.
Pero en el siguiente cdigo:

a = 10
b=5
if (a != 10) and (b == 5):
print 'Hola Mundo'

La primera condicin NO se cumple, entonces no se imprimir nada.


or evala si alguna de las condiciones se cumple. Con que una sola condicin se cumpla,
se ejecutar la accin.

a = 10
b=5
if (a != 10) or (b == 5):
print 'Hola Mundo'

Se lee: si (a es distinto que 10) o (b es igual a 5).


La primera condicin, no se cumple. Pero la segunda s se cumple. Entonces, imprimir
Hola Mundo.
not evala si la condicin NO se cumple:

a = 10
b=5
if not a == 10:
print 'Hola Mundo'

Se lee: si NO ES a igual que 10 (similar a escribir if a != 10)


Como la condicin NO se cumple, no se imprimir nada.

MTODOS DEL OBJETO STRING


Vimos anteriormente que para evaluar la respuesta dada al preguntar si se desea
guardar o no el presupuesto en un archivo, utilizamos el mtodo lower(). Este mtodo
pertenece a la clase string de Python, y su funcin es la de convertir una cadena de
texto en minsculas.
La clase string de Python, adems del mtodo lower() tiene muchos otros mtodos que
frecuentemente podrs utilizar. Para hacerlo, simplemente debes utilizar la
sintaxis: tu_cadena.metodo()
Otros mtodos de uso frecuente del objeto string son:
capitalize()

Convierte el primer carcter de una cadena en mayscula


upper()

Convierte toda la cadena a maysculas

lower()

Convierte toda la cadena a minsculas


swapcase()

Convierte minsculas a maysculas y maysculas a minsculas


Ms mtodos del objeto string, puedes verlos en este enlace.

NUEVO RETO: CONDICIONALES HASTA EN LA SOPA!


Dado el siguiente cdigo:

# edades
Ana = 43
Juan = 43
Pedro = 8
Roberto = 12
Melisa = 15
Helena = 3
if (Ana == Juan) and ((Helena < Melisa) or (Melisa < Roberto)) and not (Pedro > Roberto):
print 'Veo condicionales hasta en la sopa!'
else:
print 'Soar con condicionales'

El resultado, imprimir la frase Veo condicionales hasta en la sopa!.

EL DESAFO
Modificando nicamente un operador lgico, debes lograr que se imprima la frase
Soar con condicionales. No se puede quitar ningn operador. Solo puede cambiarse
un operador lgico por otro.

EXCEPCIONES, HELPERS Y REFACTORING

Bienvenid@s a la quinta entrega de Aprender Python Programando!


En el captulo de hoy, nos vamos a poner ms tcnicos como verdaderos
programadores. Mejoraremos no solo la funcionalidad externa de nuestro programa,
sino que adems, emplearemos tcnicas de refactoring(refactorizacin) que nos
ayuden a mejorar el rendimiento interno del programa.

QU HAREMOS HOY?
1. Agregaremos nuevas funcionalidades al programa y mejoraremos otras

existentes:
o
Haremos que tanto la fecha actual como la de caducidad de nuestro presupuesto,
se calculen de forma automtica.
o
Al finalizar la carga de un presupuesto, tendremos la opcin de abrirlo directamente
en el navegador para visualizarlo.
o
Mejoraremos el funcionamiento de la eleccin del plan a presupuestar, validando
que el dato ingresado sea correcto. De no serlo, se nos volver a pedir que
ingresemos una opcin.
2. Haremos un refactoring del cdigo, a fin de:
o
Hacer nuestro cdigo ms legible.
o
Lograr que el programa tenga un mejor rendimiento.
o
Facilitar el mantenimiento y evolucin del sistema.

INGREDIENTES

Nuestra receta del captulo hoy, necesitar nuevos archivos e incorporar


modificaciones. Lo primero que haremos es:
Descargar archivos modificados:
presupuesto.py
Descargar los archivos nuevos:
Si lo deseas, puedes modificar el nombre de la carpeta capitulo3 por el nombre que
desees otorgarle al programa, o dejarlo sin cambios y guardar los siguientes archivos,
dentro de ella.
constantes.py
helpers.py

HELPERS: UNA FORMA DE AGRUPAR FUNCIONES


GENRICAS
Hemos creado un nuevo archivo: helpers.py. En este archivo, hemos agrupadofunciones
de uso comn, que si bien hoy, son utilizadas por nuestro mdulo Presupuesto, al
ser funciones genricas (no son acciones propias del objeto presupuesto, sino que
aplicaran a cualquier otro objeto), el da de maana, podramos utilizarlas en otros
mdulos de nuestro sistema.

HELPER
En la programacin, un helper es una forma de agrupar funciones de uso comn,
destinadas a servir de ayuda a otros procesos.
Un Helper se compone de funciones genricas que se encargan de realizaracciones
complementarias, aplicables a cualquier elemento de un sistema.

Es importante mencionar, que un Helper, pueden ser, tanto funciones sueltas como la
abstraccin de un objeto helper (es decir, una clase).

class Helper:
def helper_1(self):
# algoritmo

def helper_2(self):
# algoritmo

Es tan (o ms) vlido que:

def helper_1(self):
# algoritmo

def helper_2(self):
# algoritmo

Por lo tanto, nuestro archivo helpers.py, es un mdulo que contiene ayudantes,


comunes a cualquier otro mdulo de nuestro sistema.

DOCSTRINGS Y LA FUNCIN HELP() EN PYTHON


Quieres saber de qu trata el archivo helpers.py?
1.
2.
3.
4.

Abre una terminal


Navega hasta el directorio donde tienes almacenados los mdulos del sistema
Ejecuta el intrprete interactivo de python (escribe: python)
Una vez en el intrprete, escribe:

5. import helpers

help(helpers)

El "Easter Egg" de la Gua Python

Haz visto el resultado? Sorprendente! no es cierto?


Los docstrings, no son algo nuevo. Ya los habamos visto al comienzo de la gua. Los
Docstrings no son ms que el comentario de nuestro cdigo. Y si haz probado hacer un
help(helpers), habrs podido notar la importancia de comentar nuestro cdigo.
La funcin help(), al igual int(), raw_input() y tantas otras que hemos visto, es una
funcin nativa de Python, es decir una funcin interna o funcin built-in. Si lo deseas,
es muy recomendable ver la lista completa de las funciones built-in de Python (en
ingls).
help() ha sido diseada para ejecutarse en modo interactivo. Cuando le es pasado como
parmetro, el nombre de un mdulo, objeto, clase, mtodo, funcin, etc., help()
devolver la documentacin que hayamos especificado, as como toda informacin
adicional sobre el elemento pasado como parmetro.

CONSIDERACIONES PARA ESCRIBIR DOCSTRINGS


Cuando documentes un mtodo o funcin en Python, debers escribir los docstrings
teniendo en cuenta lo siguiente:
La documentacin se escribe entre triple comillas dobles en la misma lnea,
justo despus de la definicin def
Correcto:

def mi_funcion():
"""Aqu la documentacin"""

Incorrecto:

def mi_funcion():
""" Aqu la documentacin """

def mi_funcion():
"""
Aqu la documentacin
"""

Definitivamente un homicidio que amerita prisin perpetua:

def mi_funcion():

"""

Aqu la documentacin

"""

Una buena documentacin, debe incluir la accin que realiza, lo que retorna y
los parmetros que acepta.
En estos casos, se utilizan docstrings multilnea, siguiendo el prximo esquema:

"""Hace X retorna Y

Argumentos:
arg1 -- descripcin de arg1
arg2 -- descripcin de arg2

"""

Las especificaciones para los docstrings se encuentran oficialmente documentadas


por Python en las PEP 257.

TRABAJANDO CON FECHAS EN PYTHON


Una de las modificaciones que incorporamos hoy, consiste en gestionar las fechas de
confeccin y caducidad del presupuesto, en forma automtica. Para ello, incorporamos
dos helpers:

def get_fecha_actual():
hoy = datetime.datetime.now()
fecha_actual = hoy.strftime("%d/%m/%Y")
return fecha_actual

def sumar_dias(dias=0):
fecha = datetime.datetime.now() + datetime.timedelta(days=dias)
nueva_fecha = fecha.strftime("%d/%m/%Y")
return nueva_fecha

Las fechas, podemos generarlas automticamente, gracias al mdulo datetime de


Python:

import datetime

El mtodo now() de datetime, retorna la fecha y hora actual:

hoy = datetime.datetime.now()

La funcin strftime() convierte la fecha a cadena de texto, con el formato pasado como
parmetro:

hoy.strftime("%d/%m/%Y")

Con la funcin timedelta() podemos calcular fechas, ya sea restando, como sumando,
dividiendo o multiplicando N cantidad de das:

fecha = datetime.datetime.now() + datetime.timedelta(days=dias)

EL MDULO DATETIME
Este mdulo, nativo de Python, nos permite realizar diferentes manejos con fechas.
Para utilizar el mdulo debe importarse:

import datetime

Obtener la fecha y hora actual:

datetime.datetime.now()

Sumar, restar, multiplicar o dividir N das a una fecha:

fecha operador_aritmtico datetime.datetime.timedelta(days=N)

Donde N debe ser un nmero entero (representa la cantidad de das a sumar, restar,
multiplicar o dividir). Sumar (+), Restar (-), dividir (//), multiplicar (*).
Dar formato a una fecha:

fecha.strftime(string_formato)

Donde string_formato ser la cadena de texto que defina el formato deseado, con las
directrices indicadas.

Para dar diversos formatos de fechas, las directrices disponibles, son las siguientes:

Chuleta para formato de fechas

REFACTORING
Hemos realizado algunos cambios a nuestro cdigo, pero que sin embargo, no se reflejan
al momento de utilizar el programa.

REFACTORING
Refactoring (o refactorizacin / refactorizar) es una tcnica de programacin, que
consiste en efectuar cambios al cdigo fuente, sin alterar el funcionamiento
externo del programa.

Qu cambios hemos hecho?


Eliminar de la clase todo aquello que no est relacionado de forma directa con la lgica
propia del objeto. Para ello, recurrimos a:
Refactoring #1: Eliminar la directiva print del mdulo presupuesto, movindola a un
helper.
Refactoring #2: Todos los textos a mostrar en los raw_input(), as como otros mensajes
del sistema, fueron movidos a variables de acceso global, definidas en el
archivo constantes.py. Es muy importante hacer la salvedad, de que Python, no
posee el concepto de constantes como otros lenguajes.
Hablar de constantes en Python, es una cuestin lingstica pero no tcnica. A los fines
del lenguaje, decir constante en Python, simplemente hace referencia a variables cuyo
valor, se encuentra predefinido sin necesidad de requerir modificar dinmicamente
dichos datos.
Limpiamos el mdulo, moviendo un mtodo genrico que podra utilizarse en cualquier
otro mdulo (no necesariamente Presupuesto). Para ello, recurrimos a:
Refactoring #3: mover el mtodo leer_plantilla() del mdulo Presupuesto, a un helper
llamado leer_archivo() logrando que ste, pueda ser reutilizado desde cualquier otro
mdulo.

TRATAMIENTO DE EXCEPCIONES: VALIDANDO LOS


DATOS INGRESADOS
Cuando se nos peda ingresar el cdigo de plan, se nos daban tres opciones: 0, 1 y 2.
Pero qu suceda si por error, en vez de 0, 1 2 ingresbamos otro dato?
Si ingresbamos un dato no numrico, nos generaba un error, al intentar convertirlo de
literal a entero con int(). Pero, tambin poda suceder que se ingresara un nmero mayor
que 2. En ese caso, la conversin a entero no fallara, pero al momento de intentar
acceder al plan elegido mediante self.planes[plan_elegido] nos dara un error, ya que el
ndice, estara fuera del rango de la lista.
A fin de evitar estos errores, incorporamos un algoritmo de validacin, mediante
eltratamiento de excepciones.

EXCEPCIONES
Una excepcin es un error inesperado que se produce durante la ejecucin de un
programa.

Las excepciones en Python, cuentan con dos instancias obligatorias: try y except,
donde el cdigo contenido en try intentar ejecutarse, y se falla, el error ser capturado
por except, lanzando otra accin.

try:
# intentar esto
except:
# Si lo anterior falla, capturar el error
# y hacer esto otro

Opcionalmente, en Python, pueden agregarse otras dos instancias, pero


opcionales: else y finally. Mientras que else, se encarga de ejecutar el cdigo indicado
solo si no ha fallado nada, finally, se llamar siempre (falle o no), siendo su finalidad, la
de ejecutar acciones de limpieza.

def probar_excepciones():
dato = raw_input("Ingresar numero para pasar, letra para fallar: ")
try:
int(dato)
except:
print "ejecutando execpt, try ha fallado"
else:
print "ejecutando else, try se ha logrado"
finally:
print "finally se ejecuta siempre"

Hecha esta introduccin, vayamos a nuestro mdulo Presupuesto (lneas 53 a 63):

try:
elegir_plan = int(elegir_plan)
self.plan = self.planes[elegir_plan]

Intenta convertir a entero el plan elegido en el raw_input() y despus, intentar obtener


self.planes[elegir_plan] (elegir_plan acta como nmero de ndice). Pero esta ltima, solo
se llevar a cabo, si la primera, no genera una excepcin.

except (ValueError, IndexError):


mostrar_texto(DATO_INCORRECTO)
self.seleccionar_plan()

Si se genera una excepcin, se muestra un mensaje de error y se realiza una llamada


recursiva.
Pero Qu hay all entre parntesis?
ValueError e IndexError son dos tipos de excepciones. ValueError se produce
cuando el valor tratado, no corresponde al tipo de dato esperado (por ejemplo, se
ingresa un caracter no numrico). E IndexError es el error lanzado cuando se intenta
acceder, por ejemplo, a un tem inexistente de una lista o tupla, es decir, cuando como
nmero de ndice se pasa un valor fuera del rango (es decir, mayor a la cantidad de
tems en la tupla o lista).
Si se desea capturar cualquier excepcin, se puede utilizar:

except:

Si se desea capturar nicamente un tipo de excepcin, se puede utilizar:

except TipoDeExcepcion:

Si se desean capturar varias excepciones en un mismo paso, se utiliza:

except (TipoExcepcion1, TipoExcepcion2, TipoExcepcion5):

Es posible tambin, capturar distintas excepciones en varios pa<strongsos:

except TipoExcepcion1:
#...
except (TipoExcepcion2, TipoExcepcion3):
#...
except TipoExcepcion4:
#...

Una alternativa muy til, es recoger la descripcin del error para poder mostrarla:

except TipoExcepcion, error_capturado:


print error_capturado
except (TipoExcepcion1, TipoExcepcion2), error_capturado:
print error_capturado

Finalmente, ejecutaremos el resto del script, si ninguna excepcin ha sido lanzada:

else:
datos_servicio = self.lista_precios[self.planes[elegir_plan]]

self.servicio = datos_servicio[0]
importe = datos_servicio[1]
self.importe = float(importe)

Chuleta de tipos de excepciones

WEBBROWSER: ABRIENDO EL NAVEGADOR DESDE


PYTHON
# Mostrar presupuesto en navegador
def mostrar_presupuesto(self, archivo):
respuesta = raw_input(MOSTRAR_PRESUPUESTO)

if respuesta.lower() == 's':
webbrowser.open(BASE_DIR + "/" + archivo)

(lneas 103 a 107)


Con el mdulo webbrowser nativo de Python, es posible abrir el navegador y cargar en
l, cualquier archivo HTML o direccin Web. Solo basta importar el mdulo
webbrowser import webbrowser y cargar la URL mediantewebbrowser.open(URL)

UN NUEVO DESAFO
En este captulo, hemos aprendido dos conceptos fundamentales, indispensables en la
vida de cualquier programador experto: la tcnica de refactoring y elmanejo de
excepciones. Y ninguna de las dos, es poca cosa, ni mucho menos, pueden etiquetarse
como bsicas. Los programadores que recin se inician (e incluso, puedo asegurarles
que muchos programadores con aos de experiencia), no suelen refactorizar el cdigo
fuente de sus programas, y son muy pocas las veces que manejan excepciones dentro
del cdigo.
La tarea que nos toca hoy, es animarnos a programar como verdaderos
profesionales. Cul es el desafo entonces?
Hacer un refactoring de TODOS los archivos de nuestro sistema
Cmo? Muy simple. Python, tiene una serie de recomendaciones para la escritura de
cdigo, llamada Style Guide for Python Code, definida en la PEP 8 de la cual
hemos hablado sutilmente en captulos anteriores -. Los verdaderos programadores
Python, debemos respetar esta gua de estilos al pie de la letra, ya que hacerlo,
nos garantiza que nuestro cdigo pueda ser fcilmente mantenible, legible, evolutivo y
por sobre todo, es una forma de respetarnos entre colegas. Escribir cdigo
desprolijo o con estilo propio, dificulta la lectura. Ergo, hace que entender el cdigo
escrito por otro programador, nos lleve ms trabajo.
Entonces:
1. Lee las PEP 8 (en ingls) o las PEP 7 (disponibles en espaol)
2. Revisa cuidadosamente los archivos constantes.py, helpers.py y sobre todo,
presupuesto.py (tiene violaciones a las PEP 8 de forma ex-profesa)
3. Haz todas las modificaciones que sean necesarias, para estandarizar el cdigo fuente
segn las PEP

Si no entiendes algo de las PEP pregntalo! No te quedes con la duda. Si te


aburre, o no te apasiona hacerlo o lo consideras sin sentido, ten en cuenta que hacerlo
ser fundamental para tu crecimiento profesional. Te lo garantizo!.

Es muy importante que aproveches este reto para trabajar en equipo. Puedes
utilizar los comentarios para compartir con otros programadores, las lneas de cdigo
que hayas refactorizado, as como tambin, intercambiar opiniones sobre cmo sera
mejor refactorizar tal o cual otra lnea. Aprovecha esto para entrenarte! La
capacidad para trabajar en equipo, no solo la da la buena predisposicin, sino tambin la
prctica y el intercambio con otros programadores. Y ten en cuenta, que a la hora de
buscar trabajo, sumar puntos a tus fortalezas.

HERENCIA, RELACIN ENTRE DOS O MS CLASES

Y ya hemos llegado al Captulo VI de la Gua Python!


En el captulo de hoy, agregaremos nueva funcionalidad a nuestro programa generador
de presupuestos, introduciendo con ello, un nuevo concepto de la programacin
orientada a objetos: herencia.

HERENCIA
En Programacin Orientada a Objetos, la herencia es la relacin existente entre
dos o ms clases. La herencia marca una relacin de jerarqua entre objetos, en la
cual, una clase principal (madre) puede ser heredada por otras
secundarias (hijas), las cuales adquieren por herencia los mtodos y atributos de la
primera (clase principal).

El objetivo de hoy, es utilizar esta caracterstica de la POO (la herencia), para lograr
dos tipos de presupuesto:
1. El presupuesto tradicional que venimos generando.
2. Un presupuesto extendido, que emita los recibos de pagos correspondientes, calculando el
monto de adelanto y su resto.

ARCHIVOS NECESARIOS
Utilizaremos todos los archivos disponibles en la carpeta capitulo6. En esta carpeta,
encontraremos las siguientes novedades:

UN NUEVO SUB-DIRECTORIO LLAMADO RECIBOS


En caso que decidamos ejecutar el generador de presupuestos en modo avanzado, ste,
automticamente crear y guardar los nuevos recibos en esta carpeta.

NUEVO TEMPLATE RECIBO.TXT


Este archivo es un nuevo template, el cual emplearemos como plantilla para generar los
recibos.

=====================================================
===========================
$titulo N $numero/1
=====================================================
===========================

En $ciudad a los ___ das del mes de ___________ de 20__


RECIB de $cliente
La cantidad de $moneda $pago_1
En concepto de pago adelanto presupuesto N $numero.-

________________________
$nombre
$web
=====================================================
===========================

-------------------------- >>>> cortar aqu <<<< ------------------------------

=====================================================
===========================
$titulo N $numero/2
=====================================================
===========================

En $ciudad a los ___ das del mes de ___________ de 20__


RECIB de $cliente
La cantidad de $moneda $pago_2
En concepto de pago finalizacin de obra segn presupuesto N $numero.-

________________________
$nombre
$web
=====================================================
===========================

UN NUEVO MDULO: RECIBO.PY


Este ser el archivo en el que ms nos concentraremos hoy. Un modelo que hereda de
Presupuesto, generando un presupuesto extendido que incluye formulario de recibo de
pago.

# -*- coding: utf-8 *-*

from string import Template

from presupuesto import Presupuesto


from constantes import TEMPLATE_RECIBO, CIUDAD, MONEDA_DENOMINACION
from helpers import leer_archivo

class PresupuestoConRecibo(Presupuesto):

def __init__(self):
Presupuesto.__init__(self)
self.adelanto = 40
self.titulo = "RECIBO"
self.generar_recibo()

def calcular_pagos(self):
"""Calcula el monto correspondiente al adelanto y resto del trabajo"""

total = self.neto
self.pago_1 = total * self.adelanto / 100
self.pago_2 = total - self.pago_1

def generar_recibo(self):
"""Genera los recibos para entregar al cliente"""

self.calcular_pagos()
txt = leer_archivo(TEMPLATE_RECIBO)
diccionario = dict(titulo=self.titulo,
numero=self.numero_presupuesto,
ciudad=CIUDAD,
cliente=self.cliente,
moneda=MONEDA_DENOMINACION,
pago_1=self.pago_1,
nombre=Presupuesto.encabezado_nombre,
web=Presupuesto.encabezado_web,
pago_2=self.pago_2)

txt = Template(txt).safe_substitute(diccionario)
self.guardar_recibo(txt)

def guardar_recibo(self, contenido):


"""Guarda el recibo generado en la carpeta recibos

Argumentos:

contenido -- template renderizado

"""

filename = 'recibos/' + str(self.numero_presupuesto) + '.txt'


recibo = open(filename, 'w')
recibo.write(contenido)
recibo.close()

RUN.PY
Este archivo, ser el que desde ahora en ms ejecutemos de la lnea de comandos en
lugar de presupuesto.py. Veremos como, pasndole un parmetro determinado por lnea
de comando, se encargar de ejecutar uno u otro mdulo (Presupuesto o
PresupuestoConRecibo).

# -*- coding: utf-8 *-*


import sys

from presupuesto import Presupuesto


from recibo import PresupuestoConRecibo

modelo = sys.argv[1]

if modelo == 'basico':

presupuesto = Presupuesto()
elif modelo == 'recibo':
presupuesto = PresupuestoConRecibo()
else:
print "Argumentos no vlidos"

ESE EXTRAO ARCHIVO CON EXTENSIN .NJA


El Captulo VI de la Gua Python, lo he desarrollado con el IDE Open Source,NINJA-IDE.

.
El archivo Guia_Python.nja ser opcionalmente necesario, si deseas utilizar Ninja-IDE
para esta etapa del proyecto. El archivo .nja te evitar configurar el proyecto, pero es
opcional su descarga.

ARCHIVOS MODIFICADOS
presupuesto.py
- Cdigo estandarizado segn PEP 8
- Se elimina adems, la instancia a Presupuesto incorporndola en run.py
- Se limpia el mtodo __init__()
- Ahora, Presupuesto hereda de object (ver explicacin ms adelante)
constantes.py
- Incorpora nuevas constantes

RAZONAMIENTO LGICO DE LA HERENCIA

Como bien se coment al principio, la herencia es una de las


caractersticas que define al paradigma de la Programacin Orientada a Objetos (POO),
estableciendo la forma en la cual, dos o ms clases se relacionan entre s.
Cuando una clase hereda de otra, sta, adquiere de forma automtica, los mtodos y
atributos de la clase de la cual hereda.
Existe una lgica relacional en la herencia de clases. Una clase no debe heredar al
azar de otra, sino que debe existir una relacin real.
Llevado a un ejemplo de la vida diaria, podramos tener una clase principal llamada
Persona, que sea heredada por la clase Hombre y por la clase Mujer. Hombre y Mujer,
tendran los mismos atributos que Persona (extremidades superiores, inferiores, rganos
vitales), pero cada una tendra atributos propios que las distinguen entre s y a la vez
extienden a Persona (rganos reproductores, genes). De la misma manera, compartiran
los mismas mtodos que Persona (caminar, correr, comer), pero cada una, tendran sus
propios mtodos distintivos (no, no me pidan ejemplos, usen la imaginacin!!!!).
Sin embargo, no sera relacionalmente lgico, que Perro herede de persona. Si bien
puede tener atributos y mtodos que a simple vista resultan similares (correr, comer,
caminar) no es una clase de Persona sino de Animal.

LA HERENCIA EN PYTHON
En Python, para indicar que una clase hereda de otra, se utiliza la siguiente sintaxis:

class NombreDeLaClaseHija(NombreDeLaClaseMadre):

Cuando una clase es principal (una clase madre), debe heredar de object:

class Presupuesto(object):

Nuestro nuevo mdulo recibo.py, hereda todos los atributos y mtodos de presupuesto:

class PresupuestoConRecibo(Presupuesto):

Adems, de poder definir mtodos y atributos propios que extendern las caractersticas
de Presupuesto.

ACCEDIENDO A MTODOS Y ATRIBUTOS


Para acceder a las propiedades de clase, es decir, aquellos atributos definidos en la
propia clase ANTES de ser instanciada, se utiliza:

NombreDeLaClase.nombre_del_atributo

Sin embargo, si se desea acceder a propiedades del objeto, es decir, a aquellos


atributos definidos LUEGO de crear una instancia de la clase, se utiliza:

self.nombre_del_atributo

Es decir, que dado el siguiente cdigo:

class ClaseMadre(object):

atributo_de_clase = 'valor'
def __init__(self):
self.metodo()
def metodo(self):
self.atributo_del_objeto = 'otro valor'

Si heredo esta clase, por otra:


class ClaseHija(ClaseMadre):

Para acceder a atributo_de_la_clase dentro de ClaseHija, tendr que hacerlo mediante:

print ClaseMadre.atributo_de_la_clase

Aunque tambin es posible, acceder mediante self:

print self.atributo_de_la_clase

Mientras que para acceder a atributo_del_objeto, primero se debe haber ejecutado el


mtodo que define dicha propiedad, es decir metodo():

class ClaseHija(ClaseMadre):

def __init__(self):
ClaseMadre.__init__(self)

Para luego acceder a dicho atributo, mediante self:

print self.atributo_del_objeto

Sin embargo, podr acceder a cualquier mtodo heredado, utilizando self


directamente:

class ClaseMadre(object):

atributo_de_clase = 'valor'

def __init__(self):
self.metodo()

def metodo(self):
self.atributo_del_objeto = 'otro valor'

def segundo_metodo(self):
print 'Hola Mundo'

class ClaseHija(ClaseMadre):

def __init__(self):

ClaseMadre.__init__(self)
self.otro_metodo()

def otro_metodo(self):
print ClaseMadre.atributo_de_clase
print self.atributo_del_objeto
self.segundo_metodo()

PASANDO PARMETROS A UN ARCHIVO .PY POR LNEA


DE COMANDOS
Desde ahora, para ejecutar nuestro programa, ya no tendremos que hacer python
presupuesto.py, sino:
python run.py argumento

Donde argumento podr ser: basico, quien ejecutar el mdulo Presupuesto de la


misma forma que en el Captulo V o recibo, el cual ejecutar el Presupuesto extendido
con la generacin de recibos de pago.
Si ejecutas por lnea de comandos:
presupuesto run.py recibo

Al finalizar, en la nueva carpeta recibos se habr generado un TXT con el mismo


nmero que el presupuesto creado, conteniendo dos recibos de pago para imprimir.
En cambios, si ejecutas:
presupuesto run.py basico

No habr diferencia con lo que hemos hecho hasta el captulo anterior.

CAPTURANDO ARGUMENTOS ENVIADOS POR LNEA DE


COMANDOS (EN RUN.PY)

import sys
modelo = sys.argv[1]

sys es un mdulo estndar de Python que provee de funciones especficas del sistema
(ampliar informacin).
argv recoge una lista de parmetros que son pasados por lnea de comandos cuanso se
ejecuta mediante python archivo.py argumentos.
El primer elemento de la lista argv, es decir argv[0] es el nombre del archivo. En nuestro
cdigo, accedemos directamente al segundo elemento de la lista:sys.argv[1] el cul
nos dir qu opcin hemos elegido. Si optamos por bsico, crearemos una instancia de
Presupuesto()

if modelo == 'basico':
presupuesto = Presupuesto()

En cambio, si hemos indicado recibo obtendremos una instancia de


PresupuestoConRecibo()

elif modelo == 'recibo':


presupuesto = PresupuestoConRecibo()

De lo contrario, se imprimir un mensaje de error:

else:
print "Argumentos no vlidos"

Ver ms informacin sobre paso y captura de argumentos por lnea de comando.

EL DESAFO DE HOY
Nos estamos poniendo cada vez ms exigentes con nuestro cdigo. En el captulo
anterior, nos toc hacer un refactoring para estandarizar el cdigo con la normativa de la
PEP 8.
En el captulo de hoy, el reto es doble.

DESAFO #1:
Prueba a ejecutar el mdulo run.py sin pasar ningn argumento:
python run.py

Te animas a solucionar el inconveniente con la ayuda del tutorial oficial de


Python?

DESAFO #2
El nuevo mdulo recibo.py posee un mtodo para guardar el recibo generado, muy
similar al mtodo que utiliza el mdulo Presupuesto para guardar el presupuesto en un
archivo HTML. Muchas lneas de cdigo se repiten, lo cual, incurre en una redundancia
innecesaria que puede ser evitada. Qu ideas se te ocurren para solucionar este
cdigo redundante? No es necesario que escribas cdigo. El objetivo es que entre
todos razonemos y hagamos una lluvia de ideas que nos ponga en prctica.

TESTEANDO CDIGO CON DOCTEST EN LOS COMENTARIOS

Ya estamos llegando al final de la gua Python!


En el captulo de hoy, atacaremos con una tcnica de programacin indispensable, que
nos dar una gran ventaja: evitar romper el cdigo con la incorporacin de uno nuevo
y prevenir bugs. Y de qu tcnica hablamos? Unit Testing o Test Unitarios.

TEST UNITARIOS
Los test unitarios representan un mecanismo indispensable, para probar el
funcionamiento individual, de cada parte del cdigo, previniendo que el agregado de
nuevo cdigo, haga fallar el existente.

CHANGELOG DEL CAPTULO VII

Antes de comenzar, ser necesario descargar los archivos actualizados del captulo
anterior.
A continuacin un resumen de los cambios que veremos:

capitulo6/constantes.py

Nueva constante no pblica

capitulo6/helpers.py

Agregados test con doctest

nueva funcin para guardar archivos


capitulo6/presupuesto.py

Refactoring: guardar_presupuesto()

utiliza funcin genrica para guardar


capitulo6/recibo.py

Refactoring: guardar_recibo()

utiliza funcin genrica para guardar


capitulo6/run.py
capitulo6/test/

refactoring: validacin argumentos recibidos


carpeta que contiene los test del captulo

Hoy, centraremos nuestra atencin, haciendo nfasis en los cambios realizados al


archivo helpers.py. Comencemos!

DOCTEST
doctest es un mdulo nativo de Python, que busca en los comentarios de nuestro
cdigo, fragmentos que se vean como sesiones del intrprete interactivo de Python, y
procede a ejecutar dichos fragmentos, verificando que resulten como se le ha indicado.

Esto significa, que importando el mdulo doctest, ste, buscar en los comentarios de
nuestro cdigo, todo fragmento que represente al interprete interactivo, para luego
ejecutarlo. Por ejemplo:

import doctest

def sumar_dos_numeros(a, b):


"""Suma dos nmeros y retorna su resultado

Argumentos:
a -- primer sumando
b -- segundo sumando

Test:
>>> sumar_dos_numeros(25, 10)
35
>>> sumar_dos_numeros(30, 20)
50
"""
resultado = a + b
print a + b

if __name__ == "__main__":
doctest.testmod()

Si vemos el texto debajo de Test:, luce como el intrprete interactivo.


Aqu estoy invocando a la funcin:

>>> sumar_dos_numeros(25, 10)

Aqu, estoy simulando el resultado que arrojara en el intrprete interactivo. Esto, ser
interpretado por doctest, como el resultado esperado:

35

Y finalmente, verifico que el mdulo est siendo ejecutado como script (no importado),
de ser as, doy la orden a doctest de ejecutar el script en modo test:

if __name__ == "__main__":
doctest.testmod()

COLOCANDO LOS DOCTEST EN UN ARCHIVO


INDEPENDIENTE
En nuestro ejemplo (archivo helpers.py), sin embargo, nos encontramos con estas lneas:

74
75

if __name__ == "__main__":
doctest.testfile('tests/helpers.txt')

En este caso, lo que estamos haciendo, es indicar a doctest, que nuestras pruebas se
encuentran en un archivo a parte: tests/helpers.txt Si abrimos este archivo, podremos
ver todos los test:

>>> from helpers import leer_archivo, crear_archivo, mostrar_texto

2
3

Probando leer_archivo()

4
5

>>> leer_archivo('')

'Error'

7
8

>>> leer_archivo('tests/archivo_de_prueba.txt')

'Archivo de Prueba\nHola Mundo\n'

10
11

Probando crear_archivo()

12
13

>>> crear_archivo('', 'contenido')

14

'Error'

15

>>> crear_archivo('', '')

16

'Error'

17

>>> crear_archivo('tests/archivo_de_prueba.txt', '')

18

'Error'

19

>>> crear_archivo('tests/archivo_de_prueba.txt', 'Archivo de Prueba\nHola

Mundo\n')
20
21
22

Probando mostrar_texto()

23
24

>>> mostrar_texto('Hola Mundo')

25

Hola Mundo

26

>>> mostrar_texto()

25

Si te fijas las lneas resaltadas en gris, podrs ver las llamadas a los mtodos que
estamos testeando. Mientras que las resaltadas en negro, simulan el resultando
esperado.
El texto que no aparece resaltado, es interpretado como parte de los comentarios,
exceptuando la lnea 1, que se encarga de importar los mtodos a ser testeados.

EJECUTANDO LOS TEST

Una vez que el cdigo fuente cuenta con los correspondientes test, es hora de correrlos.
Para ello, en la lnea de comandos, escribiremos:
python nombre_del_modulo_a_testear.py -v

En nuestro caso, navegaremos hasta la carpeta capitulo6 y escribiremos

python helpers.py -v

Cuando ejecutemos los test, veremos una salida similar a la siguiente:

Trying:
from helpers import leer_archivo, crear_archivo, mostrar_texto
Expecting nothing
ok
Trying:
leer_archivo('')
Expecting:
'Error'
ok
Trying:
leer_archivo('tests/archivo_de_prueba.txt')
Expecting:
'Archivo de Prueba\nHola Mundo\n'
ok
Trying:
crear_archivo('', 'contenido')
Expecting:
'Error'
ok
Trying:
crear_archivo('', '')
Expecting:
'Error'
ok
Trying:

crear_archivo('tests/archivo_de_prueba.txt', '')
Expecting:
'Error'
ok
Trying:
crear_archivo('tests/archivo_de_prueba.txt', 'Archivo de Prueba\nHola Mundo\n')
Expecting nothing
ok
Trying:
mostrar_texto('Hola Mundo')
Expecting:
Hola Mundo
ok
Trying:
mostrar_texto()
Expecting nothing
ok
1 items passed all tests:
9 tests in helpers.txt
9 tests in 1 items.
9 passed and 0 failed.
Test passed.

En lo anterior, Trying nos describe el cdigo que se est ejecutando, mientras que
Expecting, el resultado esperado. Si todo sale bien, concluir el bloque indicando ok.
Al final del test, se puede acceder al reporte completo:

1 items passed all tests:


9 tests in helpers.txt
9 tests in 1 items.
9 passed and 0 failed.

Test passed.

SOLUCIN DEL DESAFO DEL CAPTULO ANTERIOR


En el segundo desafo del captulo anterior, la propuesta era pensar como podra evitarse
la redundancia de cdigo, en los mtodos encargados de guardar los recibos y los
presupuestos en formato HTML.
Siguiendo la lnea inicial, de convertir en ayudantes genricos aquellos mtodos sin
relacin directa con el compartamiento del objeto en s mismo, se cre un helper, para
guardar dichos archivos:

47
48

def crear_archivo(ruta, contenido):


"""crea un archivo en la ruta pasada con el contenido indicado

49
50

Argumentos:

51

ruta -- ruta al archivo. Ej. carpeta/archivo.txt

52

contenido -- template renderizado

53
54

"""

55

if not ruta or not contenido:

56
57

return 'Error'
else:

58

archivo = open(ruta, 'w')

59

archivo.write(contenido)

60

archivo.close()

ANEXO DE MATERIAL DE LECTURA COMPLEMENTARIO


El desafo de hoy, no depender de resolver un problema ni de encontrar ningn tipo
de solucin puntual. El reto de hoy, consiste en desafiarte a ti mismo:

Nunca terminas de aprender y jams es suficiente lo que te ensean.


Programar, no se limita a conocer la sintaxis y funcionamiento de un lenguaje de
programacin. Siempre podrs comenzar por una gua de aprendizaje, para conocer los
caminos que puedes seguir, para convertirte en un verdadero profesional en
determinada materia. Pero eso, no debe significarlo todo.

Solo logrars ser un experto, en el momento en el que descubras, que


jams es suficiente lo que conoces y que el conocimiento no te otorga
sabidura.
Tienes una alternativa: no limitar tus recursos al mero conocimiento. No acotar tu
carrera profesional al conocer sobre un lenguaje de programacin.

De tu voluntad, depender el nivel que alcances, y de tu pasin, el


superarte cada da.
A continuacin, encontrars un listado de recurso, que no puedes dejar de leer. La gran
mayora se encuentran en espaol. Las identificadas como indispensables, te
recomiendo que hagas todo lo posible por leerlas. Las recomendadas, significa que
sera una buena idea leerlas. Y las complementarias, dependern de tu curiosidad.

EL CAMINO CORRECTO
Recurre a la razn, para asimilar lo que lees. Pero recurre a tus emociones, para
saber si lo que haces, realmente te apasiona. Solo as, sabrs que ests
siguiendo el camino correcto.

Disfruta la lectura y apasinate practicando!

LECTURA INDISPENSABLE (ES)


Gua de aprendizaje de Python por Guido van Rossum (creador de Python)
Excelente material de referencias bsicas del lenguaje.
Inmersin en Python (Dive into Python) por Mark Pilgrim
Excelente material para conocer a fondo el lenguaje y su aplicacin en la programacin
orientada a objetos.

Python no muerde por Roberto Alsina


Excelente libro para aprender a razonar ms all del lenguaje.

LECTURAS RECOMENDADAS (EN ESPAOL)


Tutorial Django por @cibernatural
Una muy buena gua para entender el funcionamiento del framework Django, ideal para
crear aplicaciones Python Web based.
Tutorial de PyGTK por John Finlay
Tutorial oficial de PyGTK, una suite de mdulos Python para crear aplicaciones de
escritorio con interfaces grficas GTK.

LECTURAS COMPLEMENTARIAS (EN ESPAOL)


Aprenda a Pensar como un Programador con Python por Allen Downey, Jeffrey
Elkner y Chris Meyers
Un libro extenso, para leer con tiempo y calma. Muy buen material para utilizar como
referencia del lenguaje. Los ltimos captulos, hacen mayor nfasis en la programacin
orientada a objetos.

LECTURAS RECOMENDADAS (EN)


MySQLdb Users Guide por Andy Dustman
Gua oficial de MySQLdb, interface para trabajar con bases de datos MySQL desde
Python.
Python doctest por Guido Van Rossum
Documentacin oficial de Python doctest
The PyQT Tutorial por ZetCode
Tutorial sobre PyQT para crear aplicaciones de escritorio con interfaces grficas (un
especial agradecimiento Jorge Courbis por pasarme el link)

QU TE GUSTARA APRENDER EN EL PRXIMO CAPTULO?

El siguiente captulo de la Gua Python te trae un desafo por adelantado. Esta vez, el
tema lo elegirs t y ser sometido a votacin, mediante una encuesta.

A continuacin, encontrars una brevsima introduccin a cada uno de los temas que
puedes elegir en la votacin. Esta introduccin te servir para poder decidirte por uno
con mayor facilidad. Recuerda que solo puedes elegir una opcin:

1. ACCESO A BASES DE DATOS CON MYSQLDB


MySQLdb es una interface para MySQL que nos permite manejar bases de datos
desde Python. Aprenderemos a conectarnos a una base de datos, leer los registros
de una tabla, insertar nuevos y editar los existentes.
Qu necesitars para seguir este captulo?
Los siguientes puntos sern necesarios para entender el captulo, ya que no sern
explicados:
o
o

Tener MySQL instalado


Conocer mnimamente la sintaxis del lenguaje SQL

2. TDD EN PYTHON CON UNITTEST


TDD (Desarrollo guiado por pruebas) y Test-First Programming, es una tcnica de
programacin que consiste en escribir tests antes de generar nuestro cdigo. Esta
tcnica de programacin, es una de las ms complejas pero es la nica que
garantiza un cdigo limpio, legible, estable y libre de errores. Aprenderemos
conceptos bsicos sobre TDD, el algoritmo de TDD, cmo escribir tests antes de
programar y ejecutar test unitarios.
Qu necesitars para seguir este captulo?
Los siguientes puntos sern necesarios para entender el captulo, ya que no sern
explicados:
o

Ganas de programar profesionalmente y estudiar algo que cuesta aprender solo.

3. INTERFACES GRFICAS PARA APLICACIONES DE


ESCRITORIO EN PYTHON
Las interfaces grficas son aquellas que te permitirn desarrollar una GUI para las
aplicaciones de escritorio desarrolladas en Python, es decir, que no corrern por
consola sino, en modo grfico. Veremos cmo mostrar texto, agregar un men
sencillo, un campo de texto y botones con WxPython y PyQT.
Qu necesitars para seguir este captulo?
Los siguientes puntos sern necesarios para entender el captulo, ya que no sern
explicados:

Nada? Ganas de ver una introduccin a interfaces grficas?

CMO VOTAR POR EL PRXIMO TEMA?


Primero, asegrate de haber ledo los detalles de cada tema en el punto anterior.
Luego, dirgete a la pgina de Facebook de Maestros del Web y vota por el tema que
quieres aprender.

INTERFACES GRFICAS CON WXPYTHON

A pedido popular, pues, ha sido votado por una amplia mayora y, a solo efecto de
cumplir por nica vez en mi vida la voluntad de las masas, en el captulo de
hoy aprenderemos veremos un ejemplo de un script Python que se ejecuta en modo
grfico! OMFG! En modo GRFICO! Jesus! Tocaremos el cielo con las manos! [apagar
modo irnico]

HOLA MUNDO EXTENDED


Haremos un Hola Mundo con wxPython, pero con algo ms que un simple Hola
Mundo.
Nuestro programa script, ser similar a un editor de textos (como el Notepad de
Gindous), con la diferencia de que por defecto, nos mostrar una plantilla decarta
comercial y la guardar automticamente en una carpeta destinada a almacenar todas
nuestras cartas.

Lo que haremos se ver as:

Para hacer este ejemplo, me inspir en la Gua oficial de Primeros Pasos con
wxPython. De esta forma, ser ms simple entender la documentacin oficial.

INSTALACIN DE WXPYTHON
El primer paso, ser instalar wxPython.
En Linux ser necesario el paquete: python-wxgtk2.8. En aquellos basados enDebian,
basta con hacer:
sudo apt-get install python-wxgtk2.8

En Gentoo:
emerge wxpython

Para RedHat, Fedora, Mandriva y compaa, pueden buscar los rpm de la versin
2.8.12.0 en este enlace www.rpmfind.net/search.php?query=wxPython o instalarlo con
yum (como root):
yum install wxPython

Para Windows y Mac OS


Descargar instalador en www.wxpython.org/download.php

Dudas/problemas sobre instalacin: Visitarhttp://wiki.wxpython.org/How


%20to%20install%20wxPython

INTRODUCCIN
wxPython es una suite de libreras de interfaces grficas para Python (programadas en
C++), destinadas a crear GUIs de forma simple. Funciona como un mdulo ms de
Python, debiendo ser importado al igual que cualquier otro.
Cmo principales caractersticas de wxPython pueden citarse:
1. Portabilidad: Windows, Linux y Mac OS X
2. Apariencia: Nativa en todos los S.O.
3. Licencia: LGPL

ARCHIVOS DEL EJEMPLO


Para nuestro creador de cartas comerciales necesitaremos 2 archivos:

constants.py
editor.py

Descargar ambos archivos, guardarlos en una carpeta y, dentro de esta, crear un subdirectorio llamado cartas. En este sub-directorio, se guardarn automticamente las
cartas que vayamos creando.
Para correrlo, simplemente haremos python editor.py y se ejecutar el script en
modo grfico.

UTILIZANDO WXPYTHON EN 6 PASOS


1. Importar wxPython:
import wx
2. Crear una clase extendida de wx.Frame:
class MiClase(wx.Frame)
3. Crear los mtodos necesarios de la clase. Aqu, adems de definir algoritmos propios,
es donde se harn las llamadas a los mtodos de wxPython y wxWidgets (ver ms
adelante)
4. Finalmente, crear una instancia de wx.App:
app = wx.App(False)
5. Otra instancia de nuestra clase:
ventana = MiClase(None, Ttulo de la ventana)
6. Llamar a MainLoop del objeto app para mantener activo el programa:
app.MainLoop()

CREANDO MTODOS DE LA CLASE


Los mtodos de la clase, lgicamente dependern de lo que queramos que nuestro
programa realice. Estos mtodos variarn de acuerdo a cada programa. Lafrmula a
seguir, ser recomendable que se desarrolle de la siguiente manera:

DEFINIR EL MTODO __INIT__


Definir el __init__ de la clase, cuyo parmetro sea (adems de self), parent. Esto
garantizar hacer siempre una referencia al elemento parent (padre) del objeto que se
est instanciando.
En nuestro caso, cuando instanciamos al editor, como ventana padre le estamos
indicando None (ninguna), ya que es la primera ventana que estamos instanciando:
frame = Editor(None, APP_TITLE)

En este ejemplo, adems, hay un segundo parmetro que corresponde al ttulo de la


ventana. Pero ste, podramos haberlo evitado, si lo definamos directamente en el
__init__. No lo hicimos, para poder extender el da de maana, este ejemplo,
instanciando otras ventanas con un nombre diferente.
En el __init__, adems, se debe inicializar al propio wx.Frame:
wx.Frame.__init__(self, parent, title=title, size=(800, 600))

Como se puede ver, a wx.Frame se le pueden pasar diversos parmetros. En nuestro


caso, un ttulo de ventana y las medidas de la misma (ancho, alto).
Es importante adems, siempre llamar al mtodo Show(), ya que de lo contrario, la
ventana nunca se visualizar:
self.Show(True)

Por otro lado, en el mtodo __init__ deben establecerse todas las propiedades de
clase y llamar a aquellos mtodos que se encarguen de generar toda la GUI.

INCRUSTANDO WIDGETS
wxPython, utiliza wxWidgets. Estos Widgets sern todos aquellos elementos que se
irn incrustando en el contenedor (frame). Una lista completa de los Widgets
implementados por wxPython, puede econtrarse
enhttp://docs.wxwidgets.org/2.8/wx_wxpython.html#wxpclasses.
Para utilizar cualquiera de estos Widgets, deben ser considerados como
mtodos de wx, simplemente utilizando la sintaxis wx.Widget(parametros).
WIDGETS UTILIZADOS EN NUESTRO CREADOR DE CARTAS COMERCIALES
En nuestro script, los widgets utilizados son:
wx.TextCtrl()
Control de entrada de texto que permite mostrar y editar su contenido. Puede ser de una
sola lnea o multilnea.
Con el parmetro value se define el contenido por defecto, mientras que styledebe ser
definido con las constantes de estilo del control.

wx.Menu()
Un men ya sea como lista desplegable o ventana emergente (pop-up) que permite
seleccionar un elemento capturando el evento y actuando en consecuencia.
wx.MenuBar()
Una barra conteniendo una serie de mens accesibles desde la parte superior de la
ventana.
wx.MessageDialog()
Un cuadro de dilogo que muestra un mensaje de una o varias lneas, con botones de
opcin como Aceptar, S, No y Cancelar. Este Widget recibe como parmetros:parent la
ventana padre, mensaje, titulo y estilo.
Ver lista completa de wxWidgets implementados por wxPython.

LLAMANDO A LOS MTODOS HEREDADOS DE WX.FRAME


wx.Frame es una clase del mdulo wx, que hereda de otras y por lo tanto, pone a
nuestra disposicin, una larga lista de mtodos, a los cules accederemos simplemente
mediante self.Metodo().
Los mtodos que utilizamos en nuestro cdigo son:
wx.Frame.CreateStatusBar()
Genera la barra de estado de la ventana.
wx.Frame.SetMenuBar()
Se encarga de crear la barra de men con todos los wxWidgets configurados.
wx.EvtHandler.Bind()
Captura un evento y lo enlaza a un controlador de eventos.
wx.SizerFlags.Centre()
Centra la ventana en el medio de la pantalla.
wx.Window.Show()
Muestra (u oculta) la ventana.
wx.Window.Close()
Cierra la ventana.

CONCLUSIN
Para utilizar cualquier interfaz grfica en Python, solo es necesario:
1. Saber Python (para programar algo y no solo mostrar ventanas con mens, textos y
botones que no hagan nada)

2. Entender la sintaxis y semntica de la programacin orientada a objetos(para


entender como funcionan las libreras grficas)
3. Tener a mano la gua de referencias de la interface grfica a utilizar(simplemente,
para saber el nombre de los mtodos y objetos a los cuales recurrir, para mostrar
grficamente aquello que tuvimos que programar en Python)

FINALIZANDO CON PYTHON Y MYSQL

Con el captulo de hoy, llegamos al final de esta gua. Considero que hemos aprendido
muchsimas cosas de gran importancia y que no solo se han enfocado en el dominio de
un lenguaje (como Python, en este caso), sino que adems, introdujeron buenas
prcticas y conceptos de la programacin en general, sus diversas tcnicas y
paradigmas.
En este ltimo episodio, nos avocaremos a un tema particular, el cual es
prcticamente imposible evitar ser abarcado en el desarrollo de un sistema informtico.
Me refiero a la interaccin con bases de datos.
Comencemos!

TRABAJANDO CON BASES DE DATOS MYSQL EN PYTHON


No abordaremos aqu, conocimientos bsicos sobre MySQL, uso, instalacin ni
configuracin. Sin perjuicio de lo anterior, har una breve introduccin.

STRUCTURED QUERY LANGUAGE (SQL)


SQL es el lenguaje de consulta estructurado utilizado para el acceso a bases de
datos relacionales. Si bien SQL como lenguaje, posee ciertos estndares, el lenguaje de
consulta en s, vara para cada base de datos en particular, siendo el tratado en este
ejemplo, el correspondiente a MySQL.

MYSQL
MySQL es un sistema de gestin de bases de datos relacionales, libre y que
puede ser instalado en mltiples plataformas.

Para seguir el captulo de esta gua, ser necesario instalar MySQL. Para ello los invito
a quienes no posean MySQL instalado, que visiten el sitio de descargas de MySQL y
la documentacin de MySQL.

MYSQLDB
MySQLdb es una interfaz para trabajar con bases de datos MySQL desde
Python. El captulo N7 de esta gua, se ha indicado como lectura recomendada,
el Manual oficial de MySQLdb el cual sugiero que se lea tras finalizar este captulo.

INSTALACIN DE MYSQLDB
Para interactuar desde Python con MySQL a travs de MySQLdb, es necesario instalar
dicho mdulo. El nombre del paquete es python-mysqldb (por si desean instalarlo
desde los repositorios), o sino, pueden descargar un tarball
desdehttp://sourceforge.net/projects/mysql-python/. All mismo, encontrarn el
archivoREADME con toda la informacin para instalarlo.

INTRODUCCIN A BASES DE DATOS CON PYTHON


En el caso particular de Python, el acceso a bases de datos se encuentra definido a
modo de estndar en las especificaciones de DB-API (por curiosidad, puedes
visitar Python Database API specification).
Esto significa, que para utilizar cualquier base de datos, siempre se debern seguir los
mismos pasos:
1. Importar el mdulo de conexin (en nuestro caso, utilizaremos MySQLdb)
import MySQLdb

2. Conectarse a la base de datos


db_host = 'localhost'
usuario = 'root'
clave = 'clave'
base_de_datos = 'mi_basededatos'
db = MySQLdb.connect(host=db_host, user=usuario, passwd=clave,
db=base_de_datos)

3. Abrir un cursor
cursor = db.cursor()

4. Ejecutar una consulta


mi_query = "SELECT campo FROM tabla WHERE campo='valor' ORDER BY campo"
cursor.execute(mi_query)

5. Si se est agregando, editando o eliminando un registro: hacer un commit a la base de


datos
db.commit()

6. Si se estn leyendo datos: obtener todos los registros hallados


cursor.fetchall()

u obtener solo el primero:


cursor.fetchone()

7. Cerrar el cursor abierto


cursor.close()

MANOS A LA OBRA!
Hecha esta introduccin, estamos en condiciones de arrancar.

CREAR LA BASE DE DATOS QUE UTILIZAREMOS


Lo primero que debemos hacer, es crear una nueva base de datos (o utilizar una
existente) y ejecutar el query (consulta) que crear la tabla que utilizaremos.
Para ello, abriendo una terminal accedes a MySQL escribiendo:

mysql -u nombre_de_usuario_de_mysql -p contrasea_de_mysql

Lgicamente, modificars nombre_de_usuario_de_mysql por tu nombre de usuario


y contrasea_de_mysql por tu clave. Al pulsar la tecla enter, versmysql>
Una vez all, si deseas crear una nueva base de datos, escribe:

create database nombre_de_la_nueva_base_de_datos;

Luego, indicamos a MySQL la base de datos que utilizaremos, escribiendo:

use nombre_de_tu_base_de_datos;

Habiendo indicado la base de datos a utilizar, ya ests en condiciones de ejecutar la


consulta que crear la tabla. Para ejecutar la consulta, copia el siguiente query y luego
pulsa la tecla enter:

CREATE TABLE IF NOT EXISTS paises (


id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
pais VARCHAR(125) NOT NULL,
abbr CHAR(2) NOT NULL
) ENGINE=InnoDB;

DESCARGAR ARCHIVOS
El ejemplo de este captulo, corresponde a un ABM de pases con arquitectura MVC
(modelo-vista-controlador). El mismo, cuenta con los siguientes archivos:

db_conn.py (Capa de abstraccin para la base de datos)


pais.py (Modelo)
pais_view.py (Vista)
pais_controller.py (Controlador)

Para ejecutar este ejemplo, llamar a pais_controller.py:


python pais_controller.py

Como podrn observar, este controlador es quien recibe las peticiones que hagamos,
encargndose de realizar los cambios necesarios al modelo (la clase Pais), llamar a este
modelo, y luego, enviar los datos necesarios a la vista, para que sta, finalmente, sea
quien nos muestre esos datos en pantalla.
Saber ms sobre el patrn arquitectnico MVC

BALANCE FINAL DE LA GUA


As es que llegamos al final de esta gua.
Queda muchsimo por aprender y sobre todo, son abundantes los consejos que
podramos tomar para crecer profesionalmente. Creo, que quienes hayan seguido la gua
paso a paso y participado activa o pasivamente de los comentarios de cada captulo,
habrn sabido comprender las bases necesarias para no ser un programador ms.
Como docente, me llevo conmigo la satisfaccin de, una vez ms, no haberme reservado
lo que aprend a lo largo de mi carrera, como un secreto bajo llave, sino, el haberlo
compartido con el solo objeto de ser aprovechado por quienes se sintiesen interesados,
curiosos, motivados, etc.

Como redactora de esta gua, quedan almacenadas en mi memoria, un cmulo de


experiencias aprovechables, producto de la interaccin humana en un medio de
comunicacin tan particular como lo es Internet.
Y como persona, me llevo la indudable realidad sobre una educacin general en
decadencia, que quisiera haber evitado conocer, pero que al mismo tiempo, me abre los
ojos a un camino alternativo para cumplir mis objetivos.
Finalmente, tras todo el balance anterior y, dadas las fechas que se aproximan, quisiera
enviar un gran saludo a judos y cristianos, ya que esta noche (25 de Kislev) comienza
, pues les deseo MUY FELIZ JANUC! a toda la cole y para este finde del 24 y 25
de diciembre, MUY FELIZ NAVIDAD! a todos los cristianos!
Y por supuesto, para todos, un EXCELENTE 2012!

DOS HROES DE PYTHON NOS CUENTAN SUS EXPERIENCIAS

Dentro de la diversidad de lenguajes que existen, Python se ha caracterizado por su


facilidad de aprendizaje y flexibilidad en el desarrollo de aplicaciones y web. Permite a
programadores principiantes entender rpidamente su sintaxis y a experimentados la
simplificacin de lineas de cdigo.

El crecimiento de su comunidad va en aumento al igual que la


presencia de aplicaciones y desarrollo web. En una entrevista Julin Amaya, co-fundador
de Monoku, nos confiesa estar enamorado de Python desde hace 3 aos y nos comenta
algunas razones del porqu est enfocado en ste lenguaje:

Una de las cosas chvere de Python es que se usa en muchas cosas, como
lenguaje es muy flexible para trabajar aplicaciones nativas y juegos.
Julin menciona tambin que algo que le gusta de Python es que permite escribir
frameworks como Django que son muy bonitos y permiten trabajar muy fcil. Opina
que el que algunas aplicaciones trabajen Python en el Frontend en vez de Javascript y

otros lenguajes que trabajan cosas que se parecen a Python muestra que Python est
aqu para quedarse y para hacer muchas cosas.

DESARROLLEMOS PROPUESTAS
Alvaro Martnez desarrolla en Python y es moderador del foro en Foros del Webdesde el
2005, nos comenta que en principio se interes mucho por HTML porque lo vea como
algo con lo que se podan lograr cosas interesantes. Tambin visitaba los foros de php y
css, sin embargo, desde hace tres aos participa activamente en el foro de Python.

Alvaro comenta que es importante que la comunidad que


programe en Python evolucione, que hayan nuevas propuestas para asegurar su avance
y desarrollo sino, por ejemplo, visitar un foro se vuelve aburrido cuando no hay ms que
las mismas preguntas por parte de los usuarios.
He mencionado algunas caractersticas positivas que nos hacen considerar aprender
Python a quienes no saben y reafirmar porqu lo hemos elegido para desarrollar, a pesar
de ellos el lenguaje tiene aspectos negativos en los cuales ambos desarrolladores estn
de acuerdo: Python tiene una comunidad grande pero carece de soporte, como
menciona Julin no es tan fcil encontrar un servidor para Python como lo es para PHP.

CMO PUEDO APRENDER PYTHON?


Python es bastante intuitivo, ambos desarrolladores comentan que aprendieron
practicando, realizando proyectos con aspectos bsicos y poco a poco mejorarlos. Si
quieres aprender Python y no conoces ningun lenguaje de programacin Julian
recomienda el libro Learn Python: The hard way que te lleva de lo bsico a lo avanzado.
Si tienes ya experiencia en algn lenguaje que no sea Python, crea un proyecto es fcil
y aprendes mientras lo desarrollas.

GUA PYTHON

En Maestros del web publicamos hace algunos meses el primer captulo de la gua
Python y an estamos en proceso de agregar ms captulos de este lenguaje. En
prximas entregas publicaremos ms captulos con autora de Alvaro Martnez.

CMO SE UTILIZA PYTHON Y DJANGO EN MEJORANDO.LA

Seguramente conoces Mejorando.la, es el proyecto web de Maestros y Cristalab.


Comenz como programa online una vez por semana y ahora se ha expandido concursos
presenciales alrededor de latinoamrica y tres conferencias con alcance mundial.
Leonidas Esteban, Renzo Avalos y Adan Sanchez son quienes hace unos meses
estuvieron trabajando para lograr el sitio que hoy se puede disfrutar al ingresar
aMejorando.la. Para lograrlo hubo todo un proceso de rediseo y reprogramacin que fue
posible gracias a varias herramientas y servicios que con la ayuda de Adan Sanchez te
contar a continuacin.

PYTHON Y DJANGO: LENGUAJE Y FRAMEWORK DE LA


MAGIA
Al momento de planear el rediseo y reprogramacion de un sitio es importante
identificar bien sus elementos y componentes principales para crear los
modelos necesarios y una buena estructura es lo primero que resalt Adn
Sanchez. Y hablando especificamente de Mejorando.la hay que destacar que el
componente principal son los videos. Desde ah parten todas las funciones que se van
agregando al sitio.
Python es el lenguaje y Django es el framework detrs del sitio de Mejorando.la. Nos
cuenta Adn que gracias a la flexibilidad que ofrece, se pudo realizar la reprogramacin
y rediseo del sitio en pocos das: Digamos que Django se ha vuelto prcticamente un
estndar como framework para desarrollo gil.

Es especialmente recomendado para un proyecto grande desarrollado por un


equipo pequeo o cuando se trata de un sitio para entregar en pocos das.
Al consultar por qu la eleccin de Django y no otro, nos explic que Django era la
solucin principal, puesto que si bien wordpress es muy flexible, en Django hay aun mas
flexibilidad.

UN FRAMEWORK CON BATERAS INCLUDAS

Django trae lo que en Python se conoce como bateras incluidas. Desde clases para
tareas sencillas como paginacin, geolocalizacin, autentificacin y cach hasta
componentes bastante completos como el mdulo de
comentarios, notificaciones, administrador, internacionalizacin y feeds.
Adn explica que un sitio en Django es ms limpio puesto que python tiene una
estructura modular, agrega que en otros lenguajes hay que descargarse muchos
archivos y el tener tantos archivos en el directorio puede hacer mas dificil manejar el
sitio. Para graficar la facilidad con la que se activan estos mdulos desde el archivo
de configuracin, nos mostr el cdigo correspondiente:

INSTALLED_APPS = (
'django.contrib.auth', # funciones de autentificacion
'django.contrib.comments', # funciones para agregar comentarios a los modelos
'django.contrib.admin', # administrador autogenerado
)

Adems afirma que es muy fcil encontrar un mdulo en los repositorios para aquellas
funcionalidades que no vienen incluidas en Django, un ejemplo de ello es el modulo
Gravatar que se utiliza en Mejorando.la para los avatares de los comentarios.

MODELO-VISTA-CONTROLADOR
Un punto ms a favor de Django es el patrn Modelo-Vista-Controlador que maneja,
esto quiere decir que separas tu aplicacin en tres componentes, explic Adn. El
modelo principal en este caso seria Video, en donde un video tiene titulo, imagen,
descripcion, comentarios.
Para entender mejor puedes ver el tercer capitulo de la guia Django y luego ver estos
ejemplos:
Modelo: son los datos, en el sitio se tiene un modelo para los Videos.
Ejemplo de modelo

class Video(models.Model):

titulo = models.CharField()
slug = models.CharField()
imagen = models.ImageField()
fecha = models.DateField()
descripcion = models.TextField()

Vista: sera la presentacin de este modelo, en Django entra en los templates, que
reciben los datos del controlador. Hay una plantilla para cada vista: home.html,
videos.html, video.html, heredando de base.html gracias al poderoso sistema de
plantillas de Django.

Controlador: se encarga de elegir los datos que se van a mostrar y hacer el


procesamiento que haga falta en estos, validacion y condicionamientos. En Mejorando.la
hay un controlador para cada pgina: home, archivo de videos y pgina de video.
Ejemplo de controlador

def video(solicitud_http, video_slug):


video = get_object_or_404(Video, slug=video_slug)
return render_to_response('website/video.html', { 'video': video })

UNIDAD, CDIGO LIMPIO Y FILTROS.


La unidad que existe en toda la plataforma es una de las caracteristicas que ms le
gust a Adn: cualquier mtodo que defina en un modelo estar presente tanto en el
controlador como en las plantillas.

Los modelos de Django permiten abstraer lo que tradicionalmente se hara con


SQL en clases y funciones. Esto permite tener un cdigo ms limpio.
Por ejemplo:

SQL
SELECT titulo, descripcion, imagen FROM videos ORDER BY fecha LIMIT 10

Django

Video.objects.all().order_by(-fecha)[:10]

Nos coment tambin que en las plantillas de Django se hace uso de la rica cantidad de
filtros que pone a disposicin, desde convertir a maysculas, eliminar etiquetas html y
agregar saltos de lnea.

Gracias a estos filtros es ms fcil tener una clara separacin entre datos, lgica
y presentacin.

SLO UN COMIENZO
Cmo te imaginars el proceso de rediseo y reprogramacin de un sitio como
Mejorando.la no se puede comentar y explicar en detalle en tan slo un artculo, sin
embargo en una proxima publicacin con Adn te contaremos ms funcionalidades y
caracteristicas que hacen de python un lenguaje fcil de aprender y de Django el
framework ideal para perfeccionistas.

SIGAMOS APRENDIENDO PYTHON

La semana pasada dos hroes de Python nos contaron sus experiencias trabajando con
el lenguaje y Gissela, con la ayuda de Adn Snchez nos mostraron cmo se utiliza
Python y Django en Mejorando.la dnde profundizamos ms en el cdigo.

NUEVOS CAPTULOS DE LA GUA PYTHON


En busca de generar mayor contenido los captulos de Python an no se han convertido
en eBook como usualmente lo hacemos, Alvaro Martnez, trabaja desde hace tres aos

con Python, es desarrollador y moderador del foro Python en Foros del Web ha realizado
4 captulos para integrar en la gua desarrollando los temas:

Conociendo a detalle las secuencias


Cadenas de texto
Expresiones regulares en Python.
Trabajando con listas, funciones y archivos.

Algunos temas que Alvaro desarrollar han sido tratados en otros captulos por Eugenia
Bahit, sin embargo, el fin es tambin aclarar algunos aspectos de forma especfica. No
olvides revisar los captulos anteriores de la gua Python:

Programacin Orientada a objetos en Python


Mtodos y Propiedades en Python
Listas, tuplas, diccionarios y estructuras de control
Trabajando con templates, archivos y condicionales
Excepciones, helpers y refactoring
Herencia, relacin entre dos o ms clases
Testeando cdigo con doctest en los comentarios
Interfaces grficas con wxPython
Finalizando con Python y MySQL

El lanzamiento del primer captulo es el mircoles 6 de junio y a partir de ese da se


publicarn semanalmente lo cuatro captulos. Qu te parecen los temas? Le seguiste la
pista a las publicaciones de Eugenia?
CONOCIENDO A FONDO EL REPOSITORIO DE MEJORANDO.LA CREADO CON PYTHON Y DJANGO

En un artculo anterior te comentamos Cmo se utiliza Python y Django en Mejorando.la,


hoy junto a Adn Sanchez seguimos comentando algunas funciones y herramientas que
se pueden ver en el repositorio Github pblico del proyecto.

LA PARTE FUNDAMENTAL DE DJANGO: EL PATRON MTV


En el articulo anterior Adn ya nos haba comentado sobre lo indispensable que es el
ceirse fielmente al patrn MTV (o MVC) al utilizar Django. Ahora hablemos de los
templates, parte importante de este patrn.
Templates
Nos dice Adn que una de las partes ms fuertes de Django es su motor de plantillas, el
mismo permite abstraer completamente la presentacin de las dems partes de la
aplicacin, esto gracias a etiquetas y filtros:
Filtros
En las plantillas de Django hacemos uso de la rica cantidad de filtros que pone a
nuestra disposicin. Desde convertir a maysculas, eliminar etiquetas html y agregar
saltos de lnea. coment Adn y agreg que gracias a estos filtros es ms fcil tener
una clara separacin entre datos, lgica y presentacin.

Para dar formato a una fecha:


Ejemplo de filtros en plantillas

<p class=fecha>{{ video.fecha|date:"F j"}}</p>

ALGUNAS BATERAS INCLUIDAS O MDULOS DJANGO


Ya habamos mencionado que Django es el framework con bateras incluidas, aqui te
comentamos algunas de ellas:
Localizacin
Nos comenta Adn sobre GeoIP, una librera de localizacin basada en C: La integracin
que trae Django con esta librera da mucho poder a la hora de crear sitios
internacionales. Agrega que esta librera bsicamente es una base de datos
gigantesca, optimizada para ser de rpido acceso, con los rangos de direcciones IP por
regiones, pases, etc.
Feed
A su vez el mdulo de sindicalizacin se cie perfectamente a los patrones propuestos
por Django, permite tener todos los mtodos y propiedades de los modelos, as como
usar plantillas y filtros para la presentacin.
Formularios
Django viene con una forma fcil de crear formularios a partir de modelos, con validacin
automtica y completamente personalizable desde la plantilla, Adn nos explica como:
Clase para formulario automtico
Un formulario es tan sencillo como:

class VideoComentarioForm(ModelForm):
class Meta:
model = VideoComentario
fields = ('autor', 'autor_email', 'autor_url', 'content')

Plantilla para personalizar formulario

<form>
<label for="author">nombre</label>{{ form.autor }}
{{ form.autor.errors }}
<label for="email">email</label>{{ form.autor_email }}
{{ form.content.errors }}

</form>

LO POCO QUE NO TIENE DJANGO, SE SOLUCIONA


Si es que Django no incluye algunos mdulos, es extremadamente sencillo crear
mdulos adicionales que encapsulen funcionalidad extra.
Imgenes
En Mejorando.la hay diferentes tipos de imgenes; estas imgenes distintas son
generadas recortando y optimizando desde el administrador, cuando se crea el video.
Nos cuenta Adn que esta tarea fue muy fcil de realizar gracias a lalibrera PIL.
Esta librera est en C por lo que es muy veloz, en Python te vas a encontrar muchos
mdulos en C, sobre todo aquellos que requieren ms procesamiento. agrega Adn.
Ejemplo de uso del mdulo PIL

import Image
image = Image.open(path)
image = image.resize((newWidth, newHeight), Image.ANTIALIAS)
image.save(path)[ ejemplo ]

CONSEJOS PARA MEJORAR LA WEB CON DJANGO Y


PYTHON
Adn nos dio algunas consideraciones para tener en cuenta al llevar el sitio a
produccin:

Configurar un administrador, que recibir alertas cuando algo salga mal.


No olvides crear tus pginas 400 y 500 (pginas de errores).
Profundizar en los mltiples parmetros de configuracin que ofrece Django. Antes de
llevar cualquier sitio Django a produccin lee la guia para que veas todo lo que puede
tweakear.
Con una lnea puedes activar el uso de memcached para cachear las pginas de
Django. Es muy simple y puede hacer una gran diferencia en el rendimiento de tu aplicacin
cuando tienes muchas visitas.
Hay muchas formas de llevar a produccin un sitio Django. Mejorando.la utiliza una
combinacin de Nginx (para archivos estticos) y mod_wsgi, que es un mdulo de apache,
para el cdigo python.
Con respecto al hosting, hostgator es una buena opcin para iniciar probando Django, sin
pagar mucho.

EL TRABAJO EN EQUIPO. NO TODO ES PROGRAMACIN


Adems de las tecnologas que mencionamos, tambin se necesitaron herramientas que
ayudaron al trabajo en equipo.
1. BaseCamp, lo ms importante es mantenerse comunicado con tu equipo.
2. Github, es una parte central para asegurar la fluidez del trabajo ya que acelera mucho el
proceso de comunicacin al llevar un registro de quin hizo qu. En Mejorando.la se
manejan dos ramas principales, hay dos sitios montados uno en desarrollo y otro que es el
produccion.
3. Feedback, al desarrollar un sitio es importante lo que opinan los usuarios, para
ello Twitter ha brindado una enorme cantidad de feedback muy valioso, nunca ignoren a
un usuario que les reporta un bug.
4. Diferentes dispositivos, cada uno de los que forman parte del equipo cuentan con
dispositivos diferentes, an as ayuda cualdo alguien manda un error con una captura de
pantalla en X dispositivo.
5. Newrelic, es una herramienta muy completa para el monitoreo del sitio.

Es importante que ests consciente de que con Django las posibilidades son
muchas, y conforme vayas profundizando en el tema irs aprendiendo trucos.
Ya sabes cmo se utiliza python, django y otras tecnologas para desarrollar el sitio
de Mejorando.la. El sitio es Open Source y el cdigo est disponible en Github.
Y si quieres profundizar ms en el tema recuerda que puedes revisar la gua Django y
la gua Python.

GUA PYTHON: CONOCIENDO A DETALLE LAS SECUENCIAS

Este captulo es complemento de la tercera parte de la gua: Listas, tuplas, diccionarios y


estructuras de control, si no lo has ledo Qu esperas?. En el tercer captulo se muestra
de forma concisa el funcionamiento de las listas y las tuplas, me propongo agregar ms
detalle a lo mencionado all. Veamos qu tienen en comn, qu tienen de diferente y
cmo Python nos permite trabajar con cadenas como si fuesen listas de caracteres.

SECUENCIAS
Listas y tuplas en Python son objetos que contienen listas de datos a los que se accede
mediante un ndice, de forma similar a los arreglos (vectores o matrices) de otros
lenguajes. Pertenecen a un tipo de datos que Python llama secuencias y que incluyen
tambin a las cadenas de texto.
Antes de entrar en las diferencias entre los tipos de secuencias, veamos lo que tienen en
comn:

No hay un lmite a la cantidad de elementos que pueden contener.


Pueden contener cualquier tipo de objeto, incluyendo otras secuencias. Por ejemplo, la
forma de crear una matriz en Python es crear una lista de listas.
No es necesario saber el tamao (cantidad de elementos) que tendr la secuencia al
momento de crearla.
Soportan algunas funciones nativas de python:
o
len(secuencia): devuelve la cantidad de elementos de la lista, tupla o cadena.
o
max(secuencia): devuelve el mayor elemento.
o
min(secuencia): devuelve el menor elemento.
Tienen dos mtodos comunes:
o
secuencia.index(x): devuelve el ndice de la primera ocurrencia de x en la
secuencia.
o
secuencia.count(x): devuelve el nmero de veces que aparece x en la
secuencia
Los elementos de la secuencia se acceden va subndices, que se indican entre corchetes
[] despus del nombre de la variable que contiene a la secuencia:
o
secuencia[0]: devuelve el primer elemento
o
secuencia[2]: devuelve el tercer elemento (notar que se numeran desde 0 y no
desde 1).
o
secuencia[i]: devuelve el elemento i-1 de la secuencia.
o
secuencia[-1]: devuelve el ltimo elemento.

Si sabes algo de PHP o Javascript vers que las secuencias en Python son muy similares
a los arreglos en estos lenguajes. Veamos ahora con ms detalles otras caractersticas
importantes de las secuencias.

JOIN (UNIN)
Podemos tomar una secuencia (cuyos elementos sean cadenas) y transformarla en una
cadena, usando la funcin join(). Esta funcin coloca un separador entre dos elementos
de la secuencia. Si guardamos nuestro separador en una variable s, debemos escribir:

s.join(secuencia)

Por ejemplo, para separar con guiones una lista de nmeros, hacemos:

>>> '-'.join(['1', '2', '3', '4', '5', '6'])


'1-2-3-4-5-6'
>>> ''.join(['1', '2', '3', '4', '5', '6']) # el separador puede ser la cadena vaca
'123456'
>>> ' es menor que '.join(['1', '2', '3', '4', '5', '6']) # o una palabra o frase completa
'1 es menor que 2 es menor que 3 es menor que 4 es menor que 5 es menor que 6'

REBANADAS (SLICES)
Se puede obtener una parte de la secuencia original usando secuencia[x:y:z],
con x, y, z enteros. Lo anterior devuelve una nueva secuencia con las siguientes
caractersticas:

Del mismo tipo que la original (una rebanada de una lista es una lista, una rebanada de
una tupla es una tupla, y una rebanada de una cadena es una cadena).
Conteniendo los elementos desde secuencia[x] hasta secuencia[y-1] (no incluye a
secuencia[y]).
Saltendose z elementos cada vez.

Por ejemplo, para obtener los nmeros impares en una lista del 1 al 10, podemos hacer
lo siguiente:

>>> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10][0:10:2] # desde el elemento 0 al elemento 9, de 2 en 2.


[1, 3, 5, 7, 9]

Para obtener el segundo y tercer elemento de una tupla:

>>> (1, 2, 3, 4)[1:3]


(2, 3)

El tercer parmetro puede omitirse y eso quiere decir que no se deben saltear elementos
(se asumir z = 1). De hecho, tambin pueden omitirse los dems: si se omite x se
tomarn todos los elementos desde el primero, y si se omite y se tomarn todos los
elementos hasta el final. Por lo tanto:
sec[:4] devuelve los primeros 4 elementos (0, 1, 2, 3).
sec[4:] devuelve los elementos desde el 5 hasta el ltimo.
sec[:] crea una secuencia con todos los elementos de la primera y es de hecho la forma

usual de copiar una secuencia.

ITERABLES
Tal y como se explic en el captulo 3, las listas y tuplas se pueden recorrer elemento a
elemento con el bucle for. La explicacin de Eugenia Bahit es muy clara, por lo que
solamente agregar que el bucle for puede recorrer cualquier tipo de secuencia, y como
las cadenas son secuencias, se las puede recorrer letra a letra:

>>> saludo = "hola"


>>> for letra in saludo:
...

print "letra = ", letra

...
letra = h
letra = o
letra = l
letra = a

OPERADOR DE PERTENENCIA
Para probar si un elemento pertenece a una secuencia, usamos el operador in. Ejemplos:

>>> 'o' in 'hola' # 'o' pertenece a la cadena 'hola'?


True

>>> 1 in (1, 2) # 1 pertenece a la tupla (1, 2)?


True
>>> 'a' in ['b', 'c'] # 'a' pertenece a la lista ['b', 'c']?
False
>>> 'a' not in ['b', 'c'] # 'a' NO pertenece a la lista ['b', 'c']?
True

CONCATENACIN (SUMA)
La suma de dos secuencias a y b genera una nueva secuencia que contiene los
elementos de ambas y en la que los elementos de b aparecen luego de los elementos
de a. Las secuencias deben ser del mismo tipo (no es posible sumar cadenas y tuplas, o
tuplas y listas, por ejemplo):

>>> 'ho' + 'la'


'hola'
>>> (1, 2) + (3, 4) + (5, 6)
(1, 2, 3, 4, 5, 6)
>>> (1, 2) + [3, 4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate tuple (not "list") to tuple

MULTIPLICACIN
Python define la multiplicacin de secuencias por un nmero entero n. El resultado de la
operacin es el mismo que el de sumar la secuencia a s misma n veces.

>>> 'a' * 5
'aaaaa'
>>> 'ab' * 2
'abab'
>>> (4, 5) * 3

(4, 5, 4, 5, 4, 5)

NOTA
Si sabes PHP, vers que lo siguiente es muy similar a cmo funciona la funcin list() de PHP.

DESEMPAQUETADO (UNPACKING)
Python permite asignar los elementos de una secuencia a diferentes variables. No se
requiere un operador especial, el desempaquetado es automtico cuando se asigna
(usando =) una secuencia a una lista de variables. De forma algo ms simple: del lado
izquierdo del signo de igual se escribe una lista de variables separadas por comas, y del
lado derecho la secuencia que ser desempaquetada.
La cantidad de variables del lado izquierdo debe ser la misma que la cantidad de
elementos de la secuencia. Como esto puede sonar complicado, mejor veamos algunos
ejemplos:

>>> a, b, c, d = 'hola'
>>> print a
'h'
>>> print b
'o'
>>> print c
'l'
>>> print d
'a'
>>> a, b = [1, 2]
>>> print a
1
>>> print b
2
>>> a, b = 'hola' #ERROR: 4 valores en la secuencia y solamente 2 variables!
Traceback (most recent call last):

File "<stdin>", line 1, in <module>


ValueError: too many values to unpack

Esto es lo que todas las secuencias tienen en comn. Veamos ahora las particularidades
de cada una.

LISTAS
Las listas en Python son equivalentes a los arreglos en PHP o en Javascript. Para crear
una lista, simplemente se declaran sus elementos entre corchetes:

>>> mi_lista = [1, 'b', 'd', 23]


>>> mi_lista_vacia = [] # crea una lista sin elementos

Para agregar elementos a una lista, se utiliza el mtodo append:

>>> mi_lista.append(10)
>>> print mi_lista
[1, 'b', 'd', 23, 10]

Para modificar un elemento particular de una lista, se asigna el nuevo valor al subndice
correspondiente:

>>> mi_lista[0] = 2
>>> print mi_lista
[2, 'b', 'd', 23, 10]

Incluso se pueden reemplazar trozos de una lista con otra, o con trozos de otra, usando
la notacin de rebanadas (slices):

>>> mi_lista[0:2] = [3, 4] # reemplazar los dos primeros elementos de la lista con los elementos de
[3, 4]
>>> print mi_lista
[3, 4, 'd', 23, 10]

Es importante notar que lo anterior no es lo mismo que asignar una secuencia entera a
un ndice:

>>> mi_lista[0] = [3, 4] # el primer elemento de mi_lista es ahora la lista [3, 4]


>>> print mi_lista
[[3, 4], 4, 'd', 23, 10]

Las listas poseen algunos mtodos propios: se puede eliminar un elemento


conmi_lista.remove(), reordenar la lista con mi_lista.sort(), o invertir el orden de sus
elementos con mi_lista.reverse(). Para una lista completa, lee la documentacin
sobre Mutable Sequence Types. Todas las secuencias pueden ser transformadas a listas
usando la funcin list().

TUPLAS
Las tuplas son como las listas, excepto que son inmutables (sus elementos no pueden
ser modificados). Se identifican fcilmente porque en vez de usar corchetes, se definen
entre parntesis. En lo dems, funcionan igual a las listas y al resto de las secuencias.

>>> mi_tupla = (3, 4, 'b', 'd')


>>> mi_tupla[2] = 'hola' # ERROR: la tupla no se puede modificar!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Python genera tuplas de forma automtica cuando encuentra valores separados por
comas en el cdigo, aunque no estn delimitados por parntesis. Esta generacin
automtica es lo contrario del desempaquetado, y se llama,
lgicamente, empaquetado (packing) de valores. Esto nos permite simular retorno de

mltiples valores en las funciones, o intercambiar los valores de dos variables sin crear
una variable auxiliar:

var1, var2 = x, y

En este caso, Python crea una tupla (x, y) (empaquetado), e inmediatamente asigna el
primer elemento a var1, y el segundo a var2 (desempaquetado)

def mi_funcion():
# cdigo de la funcin
...
return x, y

Aunque se especifiquen 2 variables, en realidad python crea la tupla (x, y) y eso es lo


que devuelve. En el cdigo que llama a la funcin, podemos escribir

var1, var2 = mi_funcion()

Gracias al desempaquetado, var1 obtiene el valor de x y var2 el de y. Todas las


secuencias pueden ser transformadas a tuplas usando la funcin tuple().

CADENAS
Las cadenas son secuencias cuyos elementos son los caracteres individuales. Por la
importancia que tiene el texto en casi cualquier programa y dado que las cadenas tienen
muchas operaciones especficas que no estn definidas para las dems secuencias.
En el captulo de la prxima semana, detallaremos las caractersticas nicas de las
cadenas de texto en Python.
VENTAJAS PARA LOS QUE SE PONEN LA CAMISETA DE PYTHON

As como apoyamos la educacin en lnea y diversos eventos de la web nos ponemos


la camiseta de algunos lenguajes y frameworks que creemos que son los que valen la
pena aprender y desarrollar.

Hoy quiero hablarte de por qu nos ponemos la camiseta de Python y Django,


contandote las ventajas y desventajas del lenguaje y del framework (respectivamente)
con la ayuda de tres programadores: Arturo Jamaica, Adn Sanchez y Ricardo Azpeitia.

DIFERENTES MOTIVOS, UN MISMO LENGUAJE.


Ricardo Azpeitia es de Monterrey, Mexico y es un destacado usuario de forosdelweb con
varios tutoriales sobre python en su haber y siempre dispuesto a responder dudas sobre
dicho lenguaje. Comenz a aprender programacin con Visual Basic y fue evolucionando
a travs de los aos, luego, desde que est en la universidad comenz a aprender
python por su cuenta.
Arturo Jamaica es de Quertaro, Mxico , tiene 22 aos, estudia ingeniera en sistemas y
es el creador de brounie.com. Comenz con python porque un compaero se lo
recomend y aunque en principio lo vi como un juego actualmente realiz varios
cursos de python con Mejorandola y estuvo en algunos programas enseando python en
20 minutos e inclusive particip de Mejorando.la Conferencia.
Adan Sanchez o mejor conocido como dual3nigma, es de Coatepec. Mxico y es uno de
los programadores del proyecto Mejorando.la. Comenz gracias a Blender (un programa
de diseo en 3D) ya que tiene como intrprete del motor de juegos a python y as como
desde hace 5 aos que trabaja con dicho lenguaje.

VAYAMOS AL GRANO, VENTAJAS Y DESVENTAJAS DE


PYTHON
Ventajas

Simplificado y rpido: Nos dice Adn que lo bueno de python es que simplifica mucho la
programacin hace que te cias a un modo de lenguaje de programacin, python te
propone un patrn. Por su parte Ricardo seala que es un gran lenguaje para scripting, si
quieres algo rpido (en el sentido del performance del lenguaje), con unas cuantas lneas ya
est.
Elegante y flexible: Para Ricardo el lenguaje te da muchas herramientas si quiero listas
de varios datos, no hace falta que declares cada cosa y agrega que al ser tan flexible no te
preocupas tanto por los detalles.
Programacin sana y productiva: Segn Arturo programar en python se convierte en
un estilo muy sano de programar: es sencillo de aprender, direccionado a las reglas
perfectas, te haces como dependiente de mejorar, cumplir las reglas, el uso de las lineas, de
variables. Adn afirma que esun lenguaje que fue hecho con productividad en
mente python me hace ser mas productivo, me permite entregar en los tiempos que me
piden.
Ordenado y limpio: Este es un punto en el cual los tres coinciden. Dice Arturo que es el
orden que mantiene python es de lo que ms le gusta es muy leible, cualquier otro
programador lo puede leer y trabajar sobre el. A su vez Adn destaca que
los mdulos estn bien organizados, a diferencia de otros lenguajes.
Portable: Tanto Arturo como Adn concuerdan en que es un lenguaje muy portable (ya
sea en mac, linux o windows) en comparacin con otros lenguajes.

Bateras incluidas: Las libreras que ms necesitas ya estn dentro del cdigo
menciona Arturo. As tambin Adn coment en detalle cules son estas bateras incluidas al
contarnos cmo se utiliza python en mejorando.la
Comunidad: Algo muy importante para el desarrollo de un lenguaje es la comunidad,
segn Arturo la misma comunidad de python cuida el lenguaje y casi todas las
actualizaciones se hacen de manera democrtica.

Desventajas
Arturo mencion que la curva de aprendizaje cuando ya ests en la parte web no es tan
sencilla. Por su parte Adn coment sobre el hecho de que la mayora de los servidores
no tienen python y si lo tienen la configuracin es un poco dificil.
Ricardo dijo que no le gustan algunas libreras que trae por defecto, por ejemplo las que
trae para trabajar con http y algunas que estn hechas por terceras personas.

HERRAMIENTAS PARA PONERSE LA CAMISETA DE


PYTHON
Hay personas que no quieren casarse con ningn lenguaje, sin embargo Arturo nos
dice que l se pone la camiseta de python y hace todo lo posible para difundir el
aprendizaje del lenguaje. As tambin nosotros, por ello si quieres ponerte la camiseta de
python puedes seguir la gua Python (que est teniendo nuevos capitulos imperdibles) y
la guia Django.
Adems puedes ver cmo se utiliza python y conocer el repositorio de mejorando.la.

GUA PYTHON: CADENAS DE TEXTO

En el captulo anterior vimos en detalle el manejo de secuencias en Python y que las


cadenas son un tipo especial de secuencia. Puede parecer extrao considerar a las
cadenas de la misma forma que las tuplas o listas, sobretodo porque se definen de una
forma tan diferente: no se separan sus elementos, por ejemplo, ni utilizan parntesis o
corchetes. Sin embargo tiene mucho sentido hacerlo, qu otra cosa es el texto sino
una secuencia de caracteres?

DEFINIENDO CADENAS
En Python tenemos varias formas ligeramente diferentes de definir cadenas. La forma
ms comn es escribirlas entre comillas dobles ():

cadena = "hola"

Tambin pueden utilizarse comillas simples (), no hay diferencia entre las cadenas
delimitadas con o .
Por razones obvias, no podemos incluir en la cadena una comilla del mismo tipo que la
que se utiliza para definirla, Python no sabr dnde termina realmente:

>>> mi_cadena = "hola "amigo" "


File "", line 1
mi_cadena = "hola "mundo" "
^
SyntaxError: invalid syntax

Una forma posible de evitar esto es delimitar la cadena con comillas simples si sabemos
que contendr comillas dobles y delimitarla con comillas dobles si sabemos que
contendr comillas simples.
Tampoco podemos incluir saltos de lnea en la cadena:

>>> mi_cadena = "hola


File "", line 1
mi_cadena = "hola
^
SyntaxError: EOL while scanning string literal

Para solucionar esto, tenemos la opcin de utilizar secuencias de escape. Las secuencias
de escape permiten introducir caracteres especiales, escapndolos(forzndolos a ser
caracteres sin significado especial) con una contrabarra (\) delante. La secuencia de
escape para un salto de lnea es \n:

>>> print "hola \n \" mundo \" " # los espacios antes y despus de \n no son necesarios, se agregan
por claridad
hola
" mundo "

Para solucionar el problema de los saltos de lnea o las comillas, podemos utilizar
tambin una tercera va: las cadenas en Python pueden delimitarse con bloques de tres
comillas dobles () o tres apstrofes (). Saltos de lnea y comillas individuales estn
permitidos en este tipo de cadenas.

>>> print """hola


"mundo" """
hola
"mundo"

Adems de todo esto, hay dos modificadores (tres en Python 3) que cambian la forma en
la que la cadena es interpretada, anteponindolos a la cadena misma:

r fuerza a que las secuencias de escape no sean interpretadas: r'hola\nmundo' no convierte


\n a un salto de lnea.
u fuerza a que la cadena sea considerada una cadena Unicode, esto habilita algunas
secuencias de escape extras y cambia la codificacin que ser utilizada para la cadena.

Podemos encontrar ms detalles sobre los modificadores, las cadenas de escape, y en


general sobre cmo se definen las cadenas en Python, en la documentacin
sobre Lexical Analysis String Literals.

INMUTABLES
En Python, as como en Java y otros lenguajes, las cadenas son inmutables (sus
elementos no se pueden modificar). Si se requieren modificaciones, se debe construir
una cadena nueva (muchas veces esto lo hace automticamente el intrprete de
Python). Ejemplo:

>>> cadena = "Hola"


>>> cadena[2] = "a"

Traceback (most recent call last):


File "", line 1, in
TypeError: 'str' object does not support item assignment
>>> print cadena[:2] + 'a' + cadena[3] # se crea una cadena nueva a partir de la original
Hoaa

MTODOS DE CADENAS
Adems de la sintaxis de subndices y rebanadas (discutidas en el captulo anterior sobre
Secuencias), las cadenas en Python tienen algunos mtodos para operaciones comunes
(bsqueda y reemplazo, por ejemplo).

BSQUEDA
Para buscar una subcadena (o un caracter) en una cadena, Python nos ofrece varias
alternativas. Si solamente necesitamos saber si una cadena contiene cierto caracter o
cierta subcadena, usamos el operador in:

>>> if 'la' in 'hola':


...

print 'Est!'

...
Est!

Si necesitamos saber adems la posicin en la que se encuentra la subcadena, usamos


los mtodos index() o find(). La diferencia entre ambos es que, si no se encuentra la
subcadena, find() devuelve -1, mientras que index() lanza una excepcin de tipo ValueError.
Ejemplos:

>>> cadena = "hola"


>>> cadena.find('ha') # 'ha' no est en 'hola', find() retorna -1
-1
>>> cadena.index('ha')

# index() lanza una excepcin

Traceback (most recent call last):

File "", line 1, in


ValueError: substring not found
>>> cadena.index('a')
3
>>> cadena.find('a') # si la cadena est, tanto index() como find() funcionan igual
3
>>> if cadena.find('ha') == -1:
...

print 'No encontrada'

...
No encontrada
>>> try:
...

cadena.index('ha')

... except ValueError:


...

print 'No encontrada'

...
No encontrada

Un uso comn de ambos mtodos es obtener toda la cadena desde el principio hasta la
primer ocurrencia de cierta subcadena:

>>> # guardamos en pos_la la posicin de 'la' en 'hola' (tercer caracter)


>>> pos_la = 'hola'.find('la')
>>> # pedimos a Python imprimir la cadena 'hola' desde el principio hasta el tercer caracter (sin
incluirlo)
>>> print 'hola'[:pos_la]
ho

Finalmente, tanto index como find aceptan parmetros que restringen la bsqueda a
cierto tramo de la cadena: en vez de buscar desde el principio y hasta el final. El
segundo argumento del mtodo indica desde qu posicin comenzar a buscar y el
tercero indica en qu posicin terminar la bsqueda.
Para ejemplificar, busquemos todas las ocurrencias de la letra e en una cadena
cualquiera (nota: hay mejores maneras de hacer esto, lo siguiente es solamente un
ejemplo!)

cadena = 'La mejor Gua de Python est en Maestros del Web!'


lista = []
pos_inicial = -1
try:
while True:
# cada vez buscamos desde un caracter ms adelante de
# la ltima ocurrencia encontrada
pos_inicial = cadena.index('e', pos_inicial+1)
lista.append(pos_inicial)
except ValueError: # cuando ya no se encuentre la letra
print 'Posiciones de la letra "e" en la cadena:', lista
Posiciones de la letra "e" en la cadena: [6, 18, 27, 33, 38, 46, 50]

REEMPLAZO DE TEXTO
Otra operacin comn es reemplazar una parte de una cadena por otra. En Python esto
lo hacemos con el mtodo replace:

>>> cadena = "Esto ser reemplazado: hola"


>>> print cadena.replace('hola', 'mundo')
Esto ser reemplazado: mundo

Notar que, como las cadenas son inmutables, el mtodo replace devuelve una nueva
cadena con el texto reemplazado, la cadena original (en el ejemplo, cadena) queda
intacta.

DIVISIN EN TROZOS
Supongamos que tenemos una cadena que contiene una fecha, en formato da/mes/ao.
Podemos obtener fcilmente cada trozo de la cadena (cada dato de la fecha) utilizando
el mtodo split. Este mtodo divide a la cadena en trozos, cortando cada trozo en cada
ocurrencia de un separador, que se pasa como argumento.

>>> fecha = '17/05/2012'


>>> datos = fecha.split('/') # separamos la cadena por /
>>> print datos
['17', '05', '2012']

# la lista contiene los trozos, sin el separador

>>> print 'da:', datos[0], 'mes:', datos[1], 'ao:', datos[2]


da: 17 mes: 05 ao: 2012

Si no le damos a split un separador, la cadena ser separada por espacios. Esto puede
servir para obtener todas las palabras de una oracin:

>>> "La mejor Gua de Python est en Maestros del Web!".split()


['La', 'mejor', 'Gua', 'de', 'Python', 'est', 'en', 'Maestros', 'del', 'Web!']

La operacin inversa (convertir una lista a cadena), se hace con el mtodo join, que
vimos en el captulo sobre Secuencias. Una advertencia a quienes programen en otros
lenguajes: la operacin join se define usualmente como una operacin de la lista, que
toma una cadena como argumento y la usa como delimitador. En Python, sin
embargo, join es una operacin de la cadena y toma una lista como argumento.
Como ejemplo, volvamos a unir la cadena de fecha, con diferentes caracteres
delimitadores:

>>> fecha = "17/05/2012"


>>> lista = fecha.split("/")
>>> print lista
['17', '05', '2012']
>>> print "-".join(lista)
17-05-2012
>>> print " ".join(lista)
17 05 2012
>>> print ", ".join(lista)
17, 05, 2012

Notar que si bien es un ejemplo claro, sera ms sencillo y eficiente hacer la sustitucin
sobre la cadena original con replace('/', '-').

CONCLUSIN
Hemos visto cmo realizar en Python algunas de las operaciones ms comunes sobre
cadenas: definicin, bsqueda, reemplazo de subcadenas y separacin en trozos.
Las cadenas tienen otros mtodos para operaciones varias, como por ejemplo buscar
desde la derecha en vez de desde la izquierda, o convertir la cadena entera o parte de
ella a maysculas o minsculas. La lista completa de mtodos est, como siempre, en la
documentacin: The string module y String methods.

GUA PYTHON: EXPRESIONES REGULARES

Cuando manejamos texto, sin duda una de las operaciones ms comunes es la bsqueda
de una subcadena, ya sea para obtener su posicin en el texto o simplemente para
comprobar si est presente. Si la cadena que buscamos es fija, son suficientes los
mtodos como find(), index() o similares, pero stos no ayudan si lo que se busca es una
subcadena con cierta forma.
Al buscar direcciones de correo electrnico, nmeros de telfono, validar campos de
entrada, o encontrar por ejemplo una letra mayscula seguida de dos minsculas y de 5
dgitos entre 1 y 3, es necesario recurrir a las Expresiones Regulares, tambin
conocidas como Patrones.

PATRONES
Las expresiones regulares son un lenguaje potente de descripcin de texto, y no creo
que exista un lenguaje moderno que no permita usarlas. Las reglas con las que se
forman son bastante simples, pero requiere prctica aprender a combinarlas
correctamente.
Con expresiones regulares podemos buscar una subcadena al principio o al final del
texto, si queremos que se repita cierta cantidad de veces, si queremos que algo NO
aparezca, o si debe aparecer una subcadena entre varias posibles. Permite adems
capturar aquellos trozos del texto que coincidan con la expresin, para guardarlos en
una variable o reemplazarlos por una cadena predeterminada (o incluso una cadena
formada por los mismos trozos capturados). Veremos algunos aspectos bsicos de las
expresiones regulares, sin entrar en detalles.

METACARACTERES
Se conoce como metacaracteres a aquellos caracteres que, dependiendo del contexto,
tienen un significado especial para las expresiones regulares, y que por lo tanto

debemos escapar (colocndoles una contrabarra \ delante) si queremos buscarlos


explcitamente. A continuacin veremos los ms importantes:

Anclas: Indican que lo que queremos encontrar se encuentra al principio o al final de la


cadena. Combinndolas, podemos buscar algo que represente a la cadena entera:
^patron:

coincide con cualquier cadena que comience con patron.


patron$: coincide con cualquier cadena que termine con patron.
^patron$: coincide con la cadena exacta patron.

Clases de caracteres: Se utilizan cuando se quiere buscar un caracter dentro de varias


posibles opciones. Una clase se delimita entre corchetes (parntesis rectos) y lista posibles
opciones para el caracter que representa:
[abc]:

coincide con a, b, o c
[387ab]: coincide con 3, 8, a o b
ni[oa]s: coincide con nios o nias.
Para evitar errores, en caso de que queramos crear una clase de caracteres que
contenga un corchete, debemos escribir una barra \ delante, para que el motor de
expresiones regulares lo considere un caracter normal: la clase[ab\[] coincide
con a, b y [.

RANGOS
Si queremos encontrar un nmero, podemos usar una clase como [0123456789], o
podemos utilizar un rango. Un rango es una clase de caracteres abreviada que se crea
escribiendo el primer caracter del rango, un guin, y el ltimo caracter del rango.
Mltiples rangos pueden definirse en la misma clase de caracteres.

[a-c]: equivale a [abc]


[0-9]: equivale a [0123456789]
[a-d5-8]: equivale a [abcd578]

Es importante notar que si se quiere buscar un guin, debe colocarse al principio o al


final de la clase (inmediatamente despus del corchete izquierdo o inmediatamente
antes del corchete derecho) o escaparse. Si no se hace de esta forma, el motor de
expresiones regulares intentar crear un rango y la expresin no funcionar como debe
(o dar un error). Si queremos, por ejemplo, crear una clase que coincida con los
caracteres a, 4 y -, debemos escribirla como:

[a4-]
[-a4]
[a\-4]

RANGO NEGADO
As como podemos listar los caracteres posibles en cierta posicin de la cadena, tambin
podemos listar caracteres que NO deben aparecer. Para lograrlo, debemosnegar la clase,
colocando un circunflejo inmediatamente despus del corchete izquierdo:

[^abc]: coincide con cualquier caracter distinto a a, b y c

CLASES PREDEFINIDAS
Hay algunas clases que se usan frecuentemente y por eso existen formas abreviadas
para ellas. En Python (as como en otros lenguajes) se soportan las clases predefinidas
de Perl y de POSIX (si no sabes lo que eso quiere decir, quizs quieras leer en Wikipedia
su signficado). Algunas de estas clases son:

\d (POSIX [[:digit:]]): equivale a [0-9]


\s (POSIX [[:space:]]): caracteres de espacio en blanco (espacio, tabulador, nueva lnea, etc)
\w (POSIX [[:word:]]): letras minsculas, maysculas, nmeros e infraguin (_)

Adems de las listadas arriba (y el resto, no listadas) existe una clase de caracteres que
coincide con cualquier caracter (sea letra, nmero, o un caracter especial). Esta clase es
el punto:

"." : coincide con cualquier caracter.

CUANTIFICADORES
Son caracteres que multiplican el patrn que les precede. Mientras que con las clases de
caracteres podemos buscar un dgito, o una letra, con los cuantificadores podemos
buscar cero o ms letras, al menos 7 dgitos, o entre tres y cinco letras maysculas.
Los cuantificadores son:

?: coincide con cero o una ocurrencia del patrn (dicho de otra forma: hace que el patrn
sea opcional)
+: coincide con una o ms ocurrencias del patrn
*: coincide con cero o ms ocurrencias del patrn.
{x}: coincide con exactamente x ocurrencias del patrn
{x, y}: coincide con al menos x y no ms de y ocurrencias. Si se omite x, el mnimo es
cero, y si se omite y, no hay mximo. Esto permite especificar a los otros como casos
particulares: ? es {0,1}, + es {1,} y * es {,} o{0,}.

Ejemplos:
: cualquier cadena, de cualquier largo (incluyendo una cadena vaca)
entre 3 y 6 letras minsculas
\d{4,}: al menos 4 dgitos
.*hola!?: una cadena cualquiera, seguida de hola, y terminando (o no) con un !
.*

[a-z]{3,6}:

OTROS METACARACTERES
Existen otros metacaracteres en el lenguaje de las expresiones regulares:

?: Adems de servir como cuantificador, puede modificar el comportamiento de otro. De

forma predeterminada, un cuantificador coincide con la mayorcadena posible; cuando se le


coloca un ?, se indica que se debe coincidir con la menor cadena posible. Esto es: dada la
cadena bbbbb, b+ coincide con la cadena entera, mientras que b+? coincide solamente
con b (la menor cadena que cumple el patrn).
(): agrupan patrones. Sirven para que aquel trozo de la cadena que coincida con el patrn
sea capturado (veremos luego cmo usar el valor capturado), o para delimitar el alcance de
un cuantificador. Ejemplo: ab+coincide con ab, abb, abbbbb, ..., mientras que (ab)+ coincide
con ab,abab, abab...
| : permite definir opciones para el patrn: perro|gato coincide con perro y con gato.

MDULO RE
Para utilizar Expresiones Regulares, Python provee el mdulo re. Importando este
mdulo podemos crear objetos de tipo patrn y generar objetos tipo matcher, que son
los que contienen la informacin de la coincidencia del patrn en la cadena.

CREANDO UN PATRN
Para crear un objeto patrn, importamos el mdulo re y utilizamos la funcincompile:

import os
patron = re.compile('a[3-5]+') # coincide con una letra, seguida de al menos 1 dgito entre 3 y 5

A partir de ahora, podemos usar el objeto patron para comparar cadenas con la
expresin regular.

BUSCAR EL PATRN EN LA CADENA


Para buscar un patrn en una cadena, Python provee los mtodos search y match. La
diferencia entre ambos es que, mientras search busca en la cadena alguna ocurrencia del
patrn, match devuelve None si la ocurrencia no se da al principio de la cadena:

>>> cadena = 'a44453'


>>> patron.match(cadena)

<_sre.SRE_Match object at 0x02303BF0>


>>> patron.search(cadena)
<_sre.SRE_Match object at 0x02303C28>
>>> cadena = 'ba3455' # la coincidencia no est al principio!
>>> patron.search(cadena)
<_sre.SRE_Match object at 0x02303BF0>
>>> print patron.match(cadena)
None

Si sabemos que obtendremos ms de una coincidencia, podemos usar el mtodofindall,


que recorre la cadena y devuelve una lista de coincidencias:

>>> patron.findall('a455 a333b435')


['a455', 'a333']

O el mtodo finditer, que devuelve un iterador que podemos usar en el bucle for:

>>> for m in patron.finditer('a455 a333b435'): # cada m es un objeto tipo matcher


... print m.groups()
...
('a', '455')
('a', '333')
('b', '435')

OBJETOS MATCHER
Ms arriba se mencion el uso del los parntesis en un patrn. Cuando se obtiene una
coincidencia del patrn en una cadena, cada grupo delimitado por parntesis captura el
texto que haya coincidido con l. Estos grupos son accesibles a travs de un objeto
tipo matcher devuelto por search o match. Los grupos se numeran de izquierda a derecha
segn su orden de aparicin en el patrn, y podemos usar este nmero para acceder al
contenido del grupo con el mtodo group del objetomatcher.

De forma alternativa, podemos usar el mtodo groups que devuelve una lista de grupos.

>>> patron = re.compile('([ab])([3-5]+)') # ahora la letra se capturar en el grupo 1, y los nmeros


en el 2
>>> matcher = patron.search('a455 a333b435')
>>> matcher.group(0) # el grupo 0 es el trozo de cadena que coincidi con el patrn completo
'a455'
>>> matcher.group(1)
'a'
>>> matcher.group(2)
'455'
>>> matcher.groups() # groups() no incluye el grupo 0
('a', '455')

Los objetos matcher guardan ms informacin sobre la coincidencia, por ejemplo la


posicin de la cadena en la que se produjo (en este caso, al principio de la cadena):

>>> matcher.pos
0

Tambin permiten sustituir los grupos capturados en una cadena cualquiera, mediante el
uso de referencias de la forma \g<x>, donde x es el nmero de grupo:

>>> print matcher.expand('La cadena que coincidi fue \g<0>, el grupo 1 es \g<1> y el grupo 2
es \g<2>')
La cadena que coincidi fue a455, el grupo 1 es a y el grupo 2 es 455

Vale notar que, si bien findall no devuelve objetos tipo matcher, s proporciona los grupos
de forma similar, como una lista de tuplas:

>>> patron.findall('a455 a333b435')

[('a', '455'), ('a', '333'), ('b', '435')]

REEMPLAZO DE CADENAS
Similar a la combinacin search + expand, existe el mtodo sub, cuya funcin es encontrar
todas las coincidencias de un patrn y sustituirlas por una cadena. El mtodo recibe dos
parmetros: el primero es la cadena con la que se sustituir el patrn y el segundo es la
cadena sobre la que queremos aplicar la sustitucin.
Se pueden utilizar referencias de la misma forma que antes:

>>> patron.sub("X", 'a455 a333b435') # sustituye todas las ocurrencias por X


'X XX'
>>> patron.sub("LETRA(\g<1>), NUMERO(\g<2>)", 'a455 a333b435') # El reemplazo depende de lo
que se capture
'LETRA(a), NUMERO(455) LETRA(a), NUMERO(333)LETRA(b), NUMERO(435)'

GRUPOS CON NOMBRE


De la misma forma en la que podemos usar grupos numerados, tambin podemos usar
grupos con nombre. Esto hace ms cmodo el manejo de patrones complejos, ya que
siempre es ms natural manejar un nombre que un nmero. Adems, si solamente
usamos nmeros de grupo, podemos tener errores si luego modificamos el patrn para
agregar algn grupo: al agregarlo bien podramos estar cambiando el ndice de otro
posterior.
Los nombres de grupo se definen agregando ?P<nombre_de_grupo> al parntesis de
apertura del grupo.

>>> patron = re.compile('(?P<letra>[ab])(?P<numero>[3-5]+)') # defino dos grupos con nombre


'letra' y 'numero'
>>> matcher = patron.search('a455 a333b435') # busco en la misma cadena de antes
>>> matcher.groups()
('a', '455')
>>> matcher.group(1)

# groups y group(n) funcionan igual

'a'
>>> matcher.group('letra') # pero adems ahora puedo acceder por nombre
'a'
>>> matcher.group('numero')
'455'
>>> matcher.expand('La letra es \g<letra>') # las referencias se usan con el nombre en vez de con
el nmero
'La letra es a'

Otra ventaja de utilizar nombres de grupo, es que podemos usar el


mtodogroupdict para obtener un diccionario de pares nombre-contenido de cada
grupo:

>>> matcher.groupdict()
{'letra': 'a', 'numero': '455'}

MODIFICADORES PARA EL PATRN


Existen varios modificadores que podemos pasar al mtodo compile para modificar el
comportamiento del patrn. Los ms usados son:

re.I o re.IGNORECASE: hace que el patrn no distinga entre minsculas y maysculas.


re.M o re.MULTILINE: modifica el comportamiento de ^ y $ para que coincidan con el

comienzo y final de cada lnea de la cadena, en vez de coincidir con el comienzo y final de la
cadena entera
re.S o re.DOTALL: hace que el punto (.) coincida adems con un salto de lnea (sin este
modificador, el punto coincide con cualquier caracter excepto un salto de lnea)

Cada modificador se usa como segundo parmetro de la funcin, podemos unir los
efectos de ms de un modificador separndolos con |. Por ejemplo:

>>> patron = re.compile('el patron', re.I | re.MULTILINE)

La lista completa est en 7.2. re Regular expression operations.


La prxima semana trabajaremos con Diccionarios, funciones y archivos en Python.

GUA PYTHON: MANEJANDO ARCHIVOS, DICCIONARIOS Y FUNCIONES

DICCIONARIOS
Conocidos en otros lenguajes como Hashes (Perl), arreglos asociativos (PHP)
ohashmaps (Java), los diccionarios en Python son contenedores de pares clave-valor. A
simple vista, son simplemente arreglos o listas cuyos ndices son cadenas en vez de ser
nmeros enteros. Internamente la diferencia es mucho mayor, ya que se implementan
como tablas hash en vez de listas. Pero no vale la pena entrar aqu en esos detalles,
cuando podemos encontrar descripciones precisas en Wikipedia: Lista, Tabla Hash.
Los diccionarios no preservan el orden de los elementos: ste depende de las claves que
se usen, del orden en el que se ingresan los datos y de otros factores. Adems, no se
puede iterar directamente sobre los elementos, aunque Python provee funciones para
hacerlo (y tambin para iterar sobre las claves).
Para crear un diccionario, escribimos los pares clave-valor entre llaves, separando cada
par por una coma:

>>> mi_diccionario = { 'nombre': 'Juan', 'apellido': 'Perez', 'pais':


'Uruguay' }
>>> print mi_diccionario['nombre']
Juan

Un diccionario puede ser expandido simplemente asignando un valor a un nuevo ndice.


Tambin podemos eliminar un valor del diccionario usando del:

>>> mi_diccionario['edad'] = 32
>>> del mi_diccionario['pais']
>>> print mi_diccionario
{'edad': 32, 'nombre': 'Juan', 'apellido': 'Perez'} # notar que se
agreg la clave 'edad', se elimin la clave 'pas', y no se preserv el
orden

Si intentamos acceder a una clave no definida, Python lanza la excepcin KeyError. Para
evitarla, podemos comprobar fcilmente si la clave est en el diccionario usando el
operador in:

>>> print mi_diccionario['una_clave_que_no_existe']


Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'una_clave_que_no_existe'
>>> if 'edad' in mi_diccionario:
...

print mi_diccionario['edad']

...
32

Otra forma de evitar el error es utilizar el mtodo get(). Este mtodo recibe dos
parmetros: la clave cuyo valor se quiere obtener y el valor a retornar si la clave no est
definida. Si no se especifica el segundo parmetro, get devuelve None:

>>> print mi_diccionario.get('edad')


32
>>> print mi_diccionario.get('una_clave_que_no_existe')
None>>> print mi_diccionario.get('una_clave_que_no_existe',
'valor predeterminado')
valor predeterminado

Al igual que las secuencias, los diccionarios tambin pueden ser recorridos con un
bucle for. La diferencia es que en vez de iterar en orden sobre los elementos, el
bucle for itera sobre las claves sin un orden preestablecido:

>>> for clave in mi_diccionario:


... print clave, ": ", mi_diccionario[clave]
...
edad : 32
nombre : Juan
apellido : Perez

Usando el mtodo items(), obtenemos una lista de tuplas (clave, valor), que podemos
usar en el for:

>>> for (clave, valor) in mi_diccionario.items():


... print clave, ": ", valor
...
edad : 32
nombre : Juanapellido : Perez

Los diccionarios soportan otras operaciones: el mtodo copy() devuelve una copia, y el
mtodo update() permite agregar a un diccionario las claves y valores de otro:

>>> dic = mi_diccionario.copy()


>>> print dic
{'edad': 32, 'nombre': 'Juan', 'apellido': 'Perez'}
>>> dic.update({'pais': 'Uruguay', 'idioma': 'Espaol' })
>>> print dic
{'edad': 32, 'nombre': 'Juan', 'idioma': 'Espaol', 'apellido': 'Perez',
'pais': 'Uruguay'}

FUNCIONES
Las funciones en Python se declaran con la palabra clave def, seguida del nombre de la
funcin y de sus argumentos. Como todo bloque en Python, la declaracin termina con
dos puntos (:) y el cdigo siguiente debe estar sangrado a un nivel mayor:

def mifuncion(parametro1, parametro2):


cdigo de la funcin

Una vez definida, la funcin puede ser llamada desde cualquier parte de nuestro archivo
Python, simplemente con su nombre. Adems de recibir valores por va de sus
parmetros, la funcin puede acceder a variables definidas fuera de ella y en el mismo
archivo (mdulo), usando la sentencia global.

Para devolver un valor, se utiliza la sentencia return. Este valor se puede obtener por
asignacin. Veamos un ejemplo:

variable_externa = 'HOLA'
def mi_funcion(param1, param2, ...):
# cdigo de la funcin
global variable_externa
return variable_externa
mifuncion(....) # ejecuta el cdigo de la funcin
mi_variable1 = mi_funcion(var1, var2, ...) # mi_variable = 'HOLA'

Vale notar que la funcin puede devolver solamente un valor (objeto), sin embargo, se
puede simular la devolucin de valores mltiples gracias al empaquetado: valores
separados por coma luego de la sentencia return se convierten a una tupla y lo que
devuelve la funcin es esa tupla. Luego podemos recibir los valores devueltos como una
tupla o desempaquetarlos:

>>> def mi_f():


...

return 'a', 'b'

...
>>> var1, var2 = mi_f() # var1 = 'a', var2 = 'b'
>>> t_var = mi_f()

# t_var: tupla formada por 'a' y 'b'

>>> t_var
('a', 'b')

Las funciones en Python pueden adems asignarse y pasarse como parmetro a otras
funciones.

MANEJANDO ARCHIVOS
En Python, as como en cualquier otro lenguaje, los archivos se manipulan en tres pasos:
primero se abren, luego se opera sobre ellos y por ltimo se cierran.

APERTURA
Para abrir un archivo debemos usar la funcin open(), que recibe como parmetros el
nombre del archivo y el modo en el que se debe abrir. De forma predeterminada (es
decir, si se omite el segundo parmetro), el archivo se abre como slo lectura.
Es importante tener en cuenta que todas las operaciones estn limitadas a la forma en la
que se abra el archivo: no se puede leer de un archivo abierto solamente para escritura,
ni escribir en un archivo abierto como solo lectura.

MODOS

r: Slo lectura. No se podr escribir en el archivo.


w: Slo escritura. Trunca el archivo al momento de abrirlo.
a: Slo escritura. Escribe al final del archivo.

En cualquiera de los modos, si el archivo no existe, es creado. Opcionalmente se puede


aadir + al modo para que se abra en modo lectura y escritura a la vez; aunque esto no
suele ser necesario y requiere cuidado para que funcione correctamente.
Otro modificador posible es b, que sirve para trabajar con archivos binarios. Esto es
necesario en Windows para manejar correctamente archivos de imgenes, o msica
(toda clase de archivos que no sean texto simple), porque el mismo SO hace diferencia
entre archivos binarios y de texto. Esto no sucede en sistemas tipo UNIX (como Mac OS,
o Linux), y por tanto en estos sistemas el modificador b no hace ninguna diferencia.

LECTURA
Una vez abierto el archivo, podemos leer el contenido hacia una cadena conread(), leer
una lnea con readline(), u obtener una lista conteniendo las lneas del archivo
con readlines(). Los tres mtodos aceptan un parmetro entero opcional que define el
nmero mximo de bytes a leer del archivo. Si este parmetro es negativo o
simplemente se omite, read y readlines leern todo el archivo yreadline una lnea completa
sin importar su largo.
Otra forma de leer el archivo es leer lnea por lnea en un bucle for, ya que el objeto
archivo es iterable.
Para ejemplificar lo mencionado hasta ahora, supongamos que tenemos un
archivoprueba.txt con el siguiente contenido:

Esto es
una prueba

de lectura!

tenemos varias formas de leerlo:

>>> archivo = open('prueba.txt', 'r') # slo lectura. Con modificadores, podra usar 'r+', 'rb', o 'rb+'
>>> print archivo.read()

# leer todo

Esto es
una prueba
de lectura!
>>> print archivo.readline()

# leer 1 lnea.

Esto es
>>> print archivo.readlines() # leer todas las lneas como una lista.
['Esto es\n', 'una prueba\n', 'de lectura!'] # ntese que siempre se
incluyen los saltos de
lnea.
>>> print archivo.read(2)

# leer como mximo 2 bytes

Es
>>> print archivo.readline(4)

# leer 1 lnea completa o 4 bytes,

lo que ocurra primero.


Esto
>>> for linea in archivo:

# con un bucle for. Esta


es la forma recomendada
de lectura por lneas.

...

print linea

...

Esto es

# Notar la lnea vaca. Esto es


porque la cadena leda incluye
un salto de lnea al final, y
print agrega otro.

una prueba
de lectura!

Es importante notar que los ejemplos anteriores no funcionan en secuencia tal cual
fueron escritos. Esto es debido a que una vez que se lee contenido del archivo, la
siguiente lectura comenzar desde donde acab la anterior. Es decir, si leemos 4 bytes
de la primera lnea (Esto), una siguiente lectura de 3 bytes devolver es. Todo
archivo contiene un puntero interno que acta como un cursor o como un punto de
partida para las funciones de lectura o escritura y a su vez cada vez que se usa una de
estas funciones, el puntero interno se mueve
Para manipular el puntero interno existen los mtodos seek, que recibe como parmetro
la posicin a la que debe mover el puntero (0 para moverlo hacia el principio del archivo)
y tell, que devuelve la posicin actual del puntero.

ESCRITURA
Si lo que queremos es escribir en el archivo, tenemos los mtodos write ywritelines.
Contrapartes de read y readlines respectivamente, write escribe una cadena al archivo
y writelines recibe una lista de lneas para escribir. Por ejemplo, si quisiramos recrear el
archivo prueba.txt del ejemplo anterior, podemos hacerlo de dos formas:

>>> archivo = open('prueba.txt', 'w') # escritura y truncado


>>> archivo.write("Esto es\nuna prueba\nde lectura!")
>>> archivo.writelines(['Esto es\n', 'una prueba\n', 'de lectura!'])
# notar la inclusin explcita de saltos de lnea
>>> archivo.close()

CIERRE
Cuando terminamos de trabajar con el archivo, lo cerramos con close(). Esto libera el
archivo para ser usado por otros programas, y adems asegura que los cambios sobre l
se guarden. De ms est decir que Python se encarga de cerrar todos los archivos que
queden abiertos al final del programa, pero es una buena prctica no dejar nada al azar
y cerrar el archivo tan pronto como se lo termina de usar.

WITH
A partir de Python 2.5, podemos simplificar un poco el cdigo necesario para abrir y
cerrar el archivo usando with:

with open('prueba.txt') as archivo:


for linea in archivo:
....

Esto nos libera de tener que cerrar el archivo explcitamente, ya que Python se
encargar de cerrarlo automticamente al salir del bloque.

Вам также может понравиться