Libro "Python para Todos"
Libro "Python para Todos"
Libro "Python para Todos"
PARA TODOS
Introducción 7
¿Qué es Python? 7
¿Por qué Python? 8
Instalación de Python 9
Herramientas básicas 10
Mi primer programa en Python 12
Tipos básicos 15
Números 16
Cadenas 21
Booleanos 22
Colecciones 24
Listas 24
Tuplas 26
Diccionarios 27
Control de flujo 29
Sentencias condicionales 29
Bucles 32
Funciones 36
Orientación a Objetos 42
Clases y objetos 42
Herencia 45
Herencia múltiple 46
Polimorfismo 47
Encapsulación 48
Clases de “nuevo-estilo” 50
Métodos especiales 50
Revisitando Objetos 53
Diccionarios 53
Cadenas 54
Listas 55
Programación funcional 57
Funciones de orden superior 57
Iteraciones de orden superior sobre listas 59
Funciones lambda 60
Comprensión de listas 61
Generadores 62
Decoradores 63
Excepciones 65
Módulos y Paquetes 72
Módulos 72
Paquetes 75
Entrada/Salida Y Ficheros 77
Entrada estándar 77
Parámetros de línea de comando 78
Salida estándar 78
Archivos 82
Expresiones Regulares 85
Patrones 85
Usando el módulo re 89
Sockets 92
Interactuar con webs 96
Threads 102
¿Qué son los procesos y los threads? 102
El GIL 103
Threads en Python 104
Sincronización 106
Datos globales independientes 111
Compartir información 111
Serialización de objetos 113
Bases de Datos 117
DB API 117
Otras opciones 124
Documentación 125
Docstrings 125
Pydoc 126
Epydoc y reStructuredText 127
Pruebas 135
Doctest 135
unittest / PyUnit 139
Distribuir aplicaciones Python 143
distutils 143
setuptools 147
Crear ejecutables .exe 152
Índice 155
Introducción
¿Qué es Python?
Python es un lenguaje de programación creado por Guido van Rossum
a principios de los años 90 cuyo nombre está inspirado en el grupo de
cómicos ingleses “Monty Python”. Es un lenguaje similar a Perl, pero
con una sintaxis muy limpia y que favorece un código legible.
Tipado dinámico
La característica de tipado dinámico se refiere a que no es necesario
declarar el tipo de dato que va a contener una determinada variable,
7
Python para todos
Fuertemente tipado
No se permite tratar a una variable como si fuera de un tipo distinto
al que tiene, es necesario convertir de forma explícita dicha variable
al nuevo tipo previamente. Por ejemplo, si tenemos una variable que
contiene un texto (variable de tipo cadena o string) no podremos tra-
tarla como un número (sumar la cadena “9” y el número 8). En otros
lenguajes el tipo de la variable cambiaría para adaptarse al comporta-
miento esperado, aunque esto es más propenso a errores.
Multiplataforma
El intérprete de Python está disponible en multitud de plataformas
(UNIX, Solaris, Linux, DOS, Windows, OS/2, Mac OS, etc.) por lo
que si no utilizamos librerías específicas de cada plataforma nuestro
programa podrá correr en todos estos sistemas sin grandes cambios.
Orientado a objetos
La orientación a objetos es un paradigma de programación en el que
los conceptos del mundo real relevantes para nuestro problema se tras-
ladan a clases y objetos en nuestro programa. La ejecución del progra-
ma consiste en una serie de interacciones entre los objetos.
Instalación de Python
Existen varias implementaciones distintas de Python: CPython,
Jython, IronPython, PyPy, etc.
9
Python para todos
Herramientas básicas
Existen dos formas de ejecutar código Python. Podemos escribir líneas
de código en el intérprete y obtener una respuesta del intérprete para
cada línea (sesión interactiva) o bien podemos escribir el código de un
programa en un archivo de texto y ejecutarlo.
In [3]: str?
10
Introducción
Type: type
Base Class:
String Form:
Namespace: Python builtin
Docstring:
str(object) -> string
11
Mi primer
programa en
Python
python hola.py
12
Mi primer programa en Python
De esta forma se mostrará una consola con el texto Hola Mundo hasta
que pulsemos Enter.
#!/usr/bin/python
print “Hola Mundo”
raw_input()
#!/usr/bin/env python
print “Hola Mundo”
raw_input()
chmod +x hola.py
./hola.py
14
Tipos básicos
# y esto es un entero
e = 23
15
Python para todos
Números
Como decíamos, en Python se pueden representar números enteros,
reales y complejos.
Enteros
Los números enteros son aquellos números positivos o negativos que
no tienen decimales (además del cero). En Python se pueden repre-
sentar mediante el tipo int (de integer, entero) o el tipo long (largo).
La única diferencia es que el tipo long permite almacenar números
más grandes. Es aconsejable no utilizar el tipo long a menos que sea
necesario, para no malgastar memoria.
16
Tipos básicos
Reales
Los números reales son los que tienen decimales. En Python se expre-
san mediante el tipo float. En otros lenguajes de programación, como
C, tenemos también el tipo double, similar a float pero de mayor
precisión (double = doble precisión). Python, sin embargo, implementa
su tipo float a bajo nivel mediante una variable de tipo double de C,
es decir, utilizando 64 bits, luego en Python siempre se utiliza doble
precisión, y en concreto se sigue el estándar IEEE 754: 1 bit para el
signo, 11 para el exponente, y 52 para la mantisa. Esto significa que los
valores que podemos representar van desde ±2,2250738585072020 x
10-308 hasta ±1,7976931348623157×10308.
real = 0.2703
17
Python para todos
real = 0.1e-3
Complejos
Los números complejos son aquellos que tienen parte imaginaria. Si
no conocías de su existencia, es más que probable que nunca lo vayas a
necesitar, por lo que puedes saltarte este apartado tranquilamente. De
hecho la mayor parte de lenguajes de programación carecen de este
tipo, aunque sea muy utilizado por ingenieros y científicos en general.
Operadores
Veamos ahora qué podemos hacer con nuestros números usando los
operadores por defecto. Para operaciones más complejas podemos
recurrir al módulo math.
Operadores aritméticos
Operador Descripción Ejemplo
+ Suma r = 3 + 2 # r es 5
- Resta r = 4 - 7 # r es -3
18
Tipos básicos
* Multiplicación r = 2 * 6 # r es 12
** Exponente r = 2 ** 6 # r es 64
% Módulo r = 7 % 2 # r es 1
r = 3.0 / 2
r = float(3) / 2
19
Python para todos
vierte todos los operandos al tipo más complejo de entre los tipos de
los operandos.
Por ejemplo, si veis una operación como 3 & 2, lo que estais viendo es
un and bit a bit entre los números binarios 11 y 10 (las representacio-
nes en binario de 3 y 2).
El operador and (&), del inglés “y”, devuelve 1 si el primer bit operando
es 1 y el segundo bit operando es 1. Se devuelve 0 en caso contrario.
El operador not (~), del inglés “no”, sirve para negar uno a uno cada
bit; es decir, si el operando es 0, cambia a 1 y si es 1, cambia a 0.
| or r = 3 | 2 # r es 3
^ xor r = 3 ^ 2 # r es 1
~ not r = ~3 # r es -4
20
Tipos básicos
Cadenas
Las cadenas no son más que texto encerrado entre comillas simples
(‘cadena’) o dobles (“cadena”). Dentro de las comillas se pueden
añadir caracteres especiales escapándolos con \, como \n, el carácter de
nueva línea, o \t, el de tabulación.
unicode = u”äóè”
raw = r”\n”
a = “uno”
b = “dos”
c = a + b # c es “unodos”
c = a * 3 # c es “unounouno”
21
Python para todos
Booleanos
Como decíamos al comienzo del capítulo una variable de tipo boolea-
no sólo puede tener dos valores: True (cierto) y False (falso). Estos
valores son especialmente importantes para las expresiones condicio-
nales y los bucles, como veremos más adelante.
En realidad el tipo bool (el tipo de los booleanos) es una subclase del
tipo int. Puede que esto no tenga mucho sentido para tí si no conoces
los términos de la orientación a objetos, que veremos más adelante,
aunque tampoco es nada importante.
Estos son los distintos tipos de operadores con los que podemos traba-
jar con valores booleanos, los llamados operadores lógicos o condicio-
nales:
22
Tipos básicos
23
Colecciones
Listas
La lista es un tipo de colección ordenada. Sería equivalente a lo que en
otros lenguajes se conoce por arrays, o vectores.
Crear una lista es tan sencillo como indicar entre corchetes, y separa-
dos por comas, los valores que queremos incluir en la lista:
l = [11, False]
mi_var = l[0] # mi_var vale 11
24
Colecciones
l = [22, True]
l[0] = 99 # Con esto l valdrá [99, True]
En todo caso las listas ofrecen mecanismos más cómodos para ser mo-
dificadas a través de las funciones de la clase correspondiente, aunque
no veremos estos mecanismos hasta más adelante, después de explicar
lo que son las clases, los objetos y las funciones.
Tuplas
Todo lo que hemos explicado sobre las listas se aplica también a las
tuplas, a excepción de la forma de definirla, para lo que se utilizan
paréntesis en lugar de corchetes.
>>> t = 1, 2, 3
>>> type(t)
type “tuple”
Además hay que tener en cuenta que es necesario añadir una coma
para tuplas de un solo elemento, para diferenciarlo de un elemento
entre paréntesis.
>>> t = (1)
>>> type(t)
26
Colecciones
type “int”
>>> t = (1,)
>>> type(t)
type “tuple”
c = “hola mundo”
c[0] # h
c[5:] # mundo
c[::3] # hauo
A cambio de estas limitaciones las tuplas son más “ligeras” que las
listas, por lo que si el uso que le vamos a dar a una colección es muy
básico, puedes utilizar tuplas en lugar de listas y ahorrar memoria.
Diccionarios
Los diccionarios, también llamados matrices asociativas, deben su
nombre a que son colecciones que relacionan una clave y un valor. Por
ejemplo, veamos un diccionario de películas y directores:
Sin embargo en este caso no se puede utilizar slicing, entre otras cosas
porque los diccionarios no son secuencias, si no mappings (mapeados,
asociaciones).
28
Control de flujo
Sentencias condicionales
Si un programa no fuera más que una lista de órdenes a ejecutar de
forma secuencial, una por una, no tendría mucha utilidad. Los con-
dicionales nos permiten comprobar condiciones y hacer que nuestro
programa se comporte de una forma u otra, que ejecute un fragmento
de código u otro, dependiendo de esta condición.
if
La forma más simple de un estamento condicional es un if (del inglés
si) seguido de la condición a evaluar, dos puntos (:) y en la siguiente
línea e indentado, el código a ejecutar en caso de que se cumpla dicha
condición.
fav = “mundogeek.net”
# si (if) fav es igual a “mundogeek.net”
if fav == “mundogeek.net”:
print “Tienes buen gusto!”
print “Gracias”
if fav == “mundogeek.net”:
print “Tienes buen gusto!”
print “Gracias”
if … else
Vamos a ver ahora un condicional algo más complicado. ¿Qué haría-
mos si quisiéramos que se ejecutaran unas ciertas órdenes en el caso de
que la condición no se cumpliera? Sin duda podríamos añadir otro if
que tuviera como condición la negación del primero:
if fav == “mundogeek.net”:
print “Tienes buen gusto!”
print “Gracias”
if fav != “mundogeek.net”:
print “Vaya, que lástima”
if fav == “mundogeek.net”:
print “Tienes buen gusto!”
print “Gracias”
else:
print “Vaya, que lástima”
30
Control de flujo
if numero < 0:
print “Negativo”
elif numero > 0:
print “Positivo”
else:
print “Cero”
elif es una contracción de else if, por lo tanto elif numero > 0 puede
leerse como “si no, si numero es mayor que 0”. Es decir, primero se
evalúa la condición del if. Si es cierta, se ejecuta su código y se con-
tinúa ejecutando el código posterior al condicional; si no se cumple,
se evalúa la condición del elif. Si se cumple la condición del elif
se ejecuta su código y se continua ejecutando el código posterior al
condicional; si no se cumple y hay más de un elif se continúa con el
siguiente en orden de aparición. Si no se cumple la condición del if ni
de ninguno de los elif, se ejecuta el código del else.
A if C else B
Bucles
Mientras que los condicionales nos permiten ejecutar distintos frag-
mentos de código dependiendo de ciertas condiciones, los bucles nos
permiten ejecutar un mismo fragmento de código un cierto número de
veces, mientras se cumpla una determinada condición.
while
El bucle while (mientras) ejecuta un fragmento de código mientras se
cumpla una condición.
edad = 0
while edad < 18:
edad = edad + 1
print “Felicidades, tienes “ + str(edad)
32
Control de flujo
Sin embargo hay situaciones en las que un bucle infinito es útil. Por
ejemplo, veamos un pequeño programa que repite todo lo que el usua-
rio diga hasta que escriba adios.
while True:
entrada = raw_input(“> “)
if entrada == “adios”:
break
else:
print entrada
salir = False
while not salir:
entrada = raw_input()
if entrada == “adios”:
salir = True
else:
print entrada
Otra palabra clave que nos podemos encontrar dentro de los bucles es
continue (continuar). Como habréis adivinado no hace otra cosa que
pasar directamente a la siguiente iteración del bucle.
edad = 0
while edad < 18:
33
Python para todos
edad = edad + 1
if edad % 2 == 0:
continue
print “Felicidades, tienes “ + str(edad)
for … in
A los que hayáis tenido experiencia previa con según que lenguajes este
bucle os va a sorprender gratamente. En Python for se utiliza como
una forma genérica de iterar sobre una secuencia. Y como tal intenta
facilitar su uso para este fin.
Como hemos dicho los for se utilizan en Python para recorrer secuen-
cias, por lo que vamos a utilizar un tipo secuencia, como es la lista, para
nuestro ejemplo.
Fácil y sencillo.
En C o C++, por ejemplo, lo que habríamos hecho sería iterar sobre las
34
Control de flujo
35
Funciones
mi_funcion(“hola”, 2)
>>> mi_funcion(“hola”)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: mi_funcion() takes exactly 2 arguments (1 given)
37
Python para todos
>>> imprimir(“hola”)
hola
>>> imprimir(“hola”, 2)
holahola
varios(1, 2)
varios(1, 2, 3)
varios(1, 2, 3, 4)
38
Funciones
varios(1, 2, tercero = 3)
x = 22
y = [22]
f(x, y)
print x, y
25 [22, 23]
22 [22, 23]
print sumar(3, 2)
Como vemos esta función tan sencilla no hace otra cosa que sumar los
valores pasados como parámetro y devolver el resultado como valor de
retorno.
a, b = f(1, 2)
Sin embargo esto no quiere decir que las funciones Python puedan de-
volver varios valores, lo que ocurre en realidad es que Python crea una
tupla al vuelo cuyos elementos son los valores a retornar, y esta única
variable es la que se devuelve.
41
Orientación a
Objetos
Clases y objetos
Para entender este paradigma primero tenemos que comprender qué es
una clase y qué es un objeto. Un objeto es una entidad que agrupa un
estado y una funcionalidad relacionadas. El estado del objeto se define
a través de variables llamadas atributos, mientras que la funcionalidad
se modela a través de funciones a las que se les conoce con el nombre
de métodos del objeto.
Una clase, por otro lado, no es más que una plantilla genérica a partir
42
Orientación a objetos
de la cuál instanciar los objetos; plantilla que es la que define qué atri-
butos y métodos tendrán los objetos de esa clase.
class Coche:
“””Abstraccion de los objetos coche.”””
def __init__(self, gasolina):
self.gasolina = gasolina
print “Tenemos”, gasolina, “litros”
def arrancar(self):
if self.gasolina > 0:
print “Arranca”
else:
print “No arranca”
def conducir(self):
if self.gasolina > 0:
self.gasolina -= 1
print “Quedan”, self.gasolina, “litros”
else:
print “No se mueve”
43
Python para todos
mi_coche = Coche(3)
44
Orientación a objetos
No se mueve
>>> mi_coche.arrancar()
No arranca
>>> print mi_coche.gasolina
0
Herencia
Hay tres conceptos que son básicos para cualquier lenguaje de pro-
gramación orientado a objetos: el encapsulamiento, la herencia y el
polimorfismo.
Para indicar que una clase hereda de otra se coloca el nombre de la cla-
se de la que se hereda entre paréntesis después del nombre de la clase:
class Instrumento:
def __init__(self, precio):
45
Python para todos
self.precio = precio
def tocar(self):
print “Estamos tocando musica”
def romper(self):
print “Eso lo pagas tu”
print “Son”, self.precio, “$$$”
class Bateria(Instrumento):
pass
class Guitarra(Instrumento):
pass
Herencia múltiple
En Python, a diferencia de otros lenguajes como Java o C#, se permite
la herencia múltiple, es decir, una clase puede heredar de varias clases a
la vez. Por ejemplo, podríamos tener una clase Cocodrilo que heredara
de la clase Terrestre, con métodos como caminar() y atributos como
velocidad_caminar y de la clase Acuatico, con métodos como nadar()
y atributos como velocidad_nadar. Basta con enumerar las clases de
46
Orientación a objetos
class Terrestre:
def desplazar(self):
print “El animal anda”
class Acuatico:
def desplazar(self):
print “El animal nada”
c = Cocodrilo()
c.desplazar()
Polimorfismo
La palabra polimorfismo, del griego poly morphos (varias formas), se re-
fiere a la habilidad de objetos de distintas clases de responder al mismo
mensaje. Esto se puede conseguir a través de la herencia: un objeto de
una clase derivada es al mismo tiempo un objeto de la clase padre, de
forma que allí donde se requiere un objeto de la clase padre también se
puede utilizar uno de la clase hija.
Encapsulación
La encapsulación se refiere a impedir el acceso a determinados mé-
todos y atributos de los objetos estableciendo así qué puede utilizarse
desde fuera de la clase.
48
Orientación a objetos
class Ejemplo:
def publico(self):
print “Publico”
def __privado(self):
print “Privado”
ej = Ejemplo()
ej.publico()
ej.__privado()
ej._Ejemplo__privado()
class Fecha():
def __init__(self):
self.__dia = 1
def getDia(self):
return self.__dia
mi_fecha = Fecha()
mi_fecha.setDia(33)
class Fecha(object):
def __init__(self):
self.__dia = 1
def getDia(self):
return self.__dia
mi_fecha = Fecha()
mi_fecha.dia = 33
Clases de “nuevo-estilo”
En el ejemplo anterior os habrá llamado la atención el hecho de que la
clase Fecha derive de object. La razón de esto es que para poder usar
propiedades la clase tiene que ser de “nuevo-estilo”, clases enriquecidas
introducidas en Python 2.2 que serán el estándar en Python 3.0 pero
que aún conviven con las clases “clásicas” por razones de retrocompa-
tibilidad. Además de las propiedades las clases de nuevo estilo añaden
otras funcionalidades como descriptores o métodos estáticos.
Para que una clase sea de nuevo estilo es necesario, por ahora, que
extienda una clase de nuevo-estilo. En el caso de que no sea necesa-
rio heredar el comportamiento o el estado de ninguna clase, como en
nuestro ejemplo anterior, se puede heredar de object, que es un objeto
vacio que sirve como base para todas las clases de nuevo estilo.
Métodos especiales
50
Orientación a objetos
__init__(self, args)
Método llamado después de crear el objeto para realizar tareas de
inicialización.
__new__(cls, args)
Método exclusivo de las clases de nuevo estilo que se ejecuta antes que
__init__ y que se encarga de construir y devolver el objeto en sí. Es
equivalente a los constructores de C++ o Java. Se trata de un método
estático, es decir, que existe con independencia de las instancias de
la clase: es un método de clase, no de objeto, y por lo tanto el primer
parámetro no es self, sino la propia clase: cls.
__del__(self)
Método llamado cuando el objeto va a ser borrado. También llamado
destructor, se utiliza para realizar tareas de limpieza.
__str__(self)
Método llamado para crear una cadena de texto que represente a nues-
tro objeto. Se utiliza cuando usamos print para mostrar nuestro objeto
o cuando usamos la función str(obj) para crear una cadena a partir de
nuestro objeto.
__cmp__(self, otro)
Método llamado cuando se utilizan los operadores de comparación
para comprobar si nuestro objeto es menor, mayor o igual al objeto
pasado como parámetro. Debe devolver un número negativo si nuestro
objeto es menor, cero si son iguales, y un número positivo si nuestro
objeto es mayor. Si este método no está definido y se intenta com-
parar el objeto mediante los operadores <, <=, > o >= se lanzará una
excepción. Si se utilizan los operadores == o != para comprobar si dos
objetos son iguales, se comprueba si son el mismo objeto (si tienen el
mismo id).
__len__(self)
Método llamado para comprobar la longitud del objeto. Se utiliza, por
51
Python para todos
52
Revisitando
Objetos
Ahora que sabemos qué son las clases, los objetos, las funciones, y los
métodos es el momento de revisitar estos objetos para descubrir su
verdadero potencial.
Diccionarios
D.get(k[, d])
Busca el valor de la clave k en el diccionario. Es equivalente a utilizar
D[k] pero al utilizar este método podemos indicar un valor a devolver
por defecto si no se encuentra la clave, mientras que con la sintaxis
D[k], de no existir la clave se lanzaría una excepción.
D.has_key(k)
Comprueba si el diccionario tiene la clave k. Es equivalente a la sin-
taxis k in D.
D.items()
Devuelve una lista de tuplas con pares clave-valor.
53
Python para todos
D.keys()
Devuelve una lista de las claves del diccionario.
D.pop(k[, d])
Borra la clave k del diccionario y devuelve su valor. Si no se encuentra
dicha clave se devuelve d si se especificó el parámetro o bien se lanza
una excepción.
D.values()
Devuelve una lista de los valores del diccionario.
Cadenas
S.count(sub[, start[, end]])
Devuelve el número de veces que se encuentra sub en la cadena. Los
parámetros opcionales start y end definen una subcadena en la que
buscar.
S.join(sequence)
Devuelve una cadena resultante de concatenar las cadenas de la se-
cuencia seq separadas por la cadena sobre la que se llama el método.
S.partition(sep)
Busca el separador sep en la cadena y devuelve una tupla con la sub-
cadena hasta dicho separador, el separador en si, y la subcadena del
separador hasta el final de la cadena. Si no se encuentra el separador, la
tupla contendrá la cadena en si y dos cadenas vacías.
S.split([sep [,maxsplit]])
Devuelve una lista conteniendo las subcadenas en las que se divide
nuestra cadena al dividirlas por el delimitador sep. En el caso de que
54
Revisitando objetos
Listas
L.append(object)
Añade un objeto al final de la lista.
L.count(value)
Devuelve el número de veces que se encontró value en la lista.
L.extend(iterable)
Añade los elementos del iterable a la lista.
L.insert(index, object)
Inserta el objeto object en la posición index.
L.pop([index])
Devuelve el valor en la posición index y lo elimina de la lista. Si no se
especifica la posición, se utiliza el último elemento de la lista.
L.remove(value)
Eliminar la primera ocurrencia de value en la lista.
L.reverse()
Invierte la lista. Esta función trabaja sobre la propia lista desde la que
se invoca el método, no sobre una copia.
55
Python para todos
Por último, si se especifica, el parámetro key debe ser una función que
tome un elemento de la lista y devuelva una clave a utilizar a la hora de
comparar, en lugar del elemento en si.
56
Programación
funcional
def saludar(lang):
def saludar_es():
57
Python para todos
print “Hola”
def saludar_en():
print “Hi”
def saludar_fr():
print “Salut”
f = saludar(“es”)
f()
>>> saludar(“en”)()
Hi
>>> saludar(“fr”)()
Salut
58
Programación funcional
def cuadrado(n):
return n ** 2
l = [1, 2, 3]
l2 = map(cuadrado, l)
filter(function, sequence)
La funcion filter verifica que los elementos de una secuencia cum-
plan una determinada condición, devolviendo una secuencia con los
elementos que cumplen esa condición. Es decir, para cada elemento de
sequence se aplica la función function; si el resultado es True se añade
a la lista y en caso contrario se descarta.
def es_par(n):
return (n % 2.0 == 0)
l = [1, 2, 3]
59
Python para todos
l2 = filter(es_par, l)
l = [1, 2, 3]
l2 = reduce(sumar, l)
Funciones lambda
El operador lambda sirve para crear funciones anónimas en línea. Al ser
funciones anónimas, es decir, sin nombre, estas no podrán ser referen-
ciadas más tarde.
l = [1, 2, 3]
l2 = filter(lambda n: n % 2.0 == 0, l)
def es_par(n):
return (n % 2.0 == 0)
l = [1, 2, 3]
l2 = filter(es_par, l)
60
Programación funcional
expresión.
Comprensión de listas
En Python 3000 map, filter y reduce perderán importancia. Y aun-
que estas funciones se mantendrán, reduce pasará a formar parte del
módulo functools, con lo que quedará fuera de las funciones dispo-
nibles por defecto, y map y filter se desaconsejarán en favor de las list
comprehensions o comprensión de listas.
l2 = [n ** 2 for n in l]
l2 = [n for n in l if n % 2.0 == 0]
61
Python para todos
l = [0, 1, 2, 3]
m = [“a”, “b”]
n = [s * v for s in m
for v in l
if v > 0]
l = [0, 1, 2, 3]
m = [“a”, “b”]
n = []
for s in m:
for v in l:
if v > 0:
n.append(s* v)
Generadores
Las expresiones generadoras funcionan de forma muy similar a la
comprensión de listas. De hecho su sintaxis es exactamente igual, a
excepción de que se utilizan paréntesis en lugar de corchetes:
l2 = (n ** 2 for n in l)
>>> l2 = [n ** 2 for n in l]
>>> l2
[0, 1, 4, 9]
>>> l2 = (n ** 2 for n in l)
>>> l2
<generator object at 0×00E33210>
62
Programación funcional
>>> x = mi_generador(0, 5, 1)
>>> x
<generator object at 0×00E25710>
lista = list(mi_generador)
Decoradores
Un decorador no es es mas que una función que recibe una función
como parámetro y devuelve otra función como resultado. Por ejem-
plo podríamos querer añadir la funcionalidad de que se imprimiera el
nombre de la función llamada por motivos de depuración:
def mi_decorador(funcion):
def nueva(*args):
print “Llamada a la funcion”, funcion.__name__
retorno = funcion(*args)
return retorno
return nueva
63
Python para todos
Supongamos como ejemplo una función imp que no hace otra cosa que
mostrar en pantalla la cadena pasada como parámetro.
>>> imp(“hola”)
hola
>>> mi_decorador(imp)(“hola”)
Llamada a la función imp
hola
@mi_decorador
def imp(s):
print s
De esta forma cada vez que se llame a imp se estará llamando realmen-
te a la versión decorada. Python incorpora esta sintaxis desde la versión
2.4 en adelante.
@otro_decorador
@mi_decorador
def imp(s):
print s
64
Excepciones
def calcular():
division(1, 0)
calcular()
$ python ejemplo.py
Traceback (most recent call last):
File “ejemplo.py”, line 7, in
calcular()
File “ejemplo.py”, line 5, in calcular
division(1, 0)
File “ejemplo.py”, line 2, in division
a / b
ZeroDivisionError: integer division or modulo by zero
65
Python para todos
try:
f = file(“archivo.txt”)
except:
print “El archivo no existe”
try:
num = int(“3a”)
print no_existe
except NameError:
print “La variable no existe”
except ValueError:
print “El valor no es un numero”
66
Excepciones
Además podemos hacer que un mismo except sirva para tratar más
de una excepción usando una tupla para listar los tipos de error que
queremos que trate el bloque:
try:
num = int(“3a”)
print no_existe
except (NameError, ValueError):
print “Ocurrio un error”
try:
num = 33
except:
print “Hubo un error!”
else:
print “Todo esta bien”
try:
z = x / y
except ZeroDivisionError:
print “Division por cero”
finally:
print “Limpiando”
class MiError(Exception):
def __init__(self, valor):
self.valor = valor
67
Python para todos
def __str__(self):
return “Error “ + str(self.valor)
try:
if resultado > 20:
raise MiError(33)
except MiError, e:
print e
68
Excepciones
70
Excepciones
71
Módulos y
Paquetes
Módulos
Para facilitar el mantenimiento y la lectura los programas demasiado
largos pueden dividirse en módulos, agrupando elementos relaciona-
dos. Los módulos son entidades que permiten una organización y divi-
sión lógica de nuestro código. Los ficheros son su contrapartida física:
cada archivo Python almacenado en disco equivale a un módulo.
def mi_funcion():
print “una funcion”
class MiClase:
def __init__(self):
print “una clase”
import modulo
72
Módulos y paquetes
modulo.mi_funcion()
print time.asctime()
print asctime()
73
Python para todos
if __name__ == “__main__”:
print “Se muestra si no es importacion”
74
Módulos y paquetes
Paquetes
Si los módulos sirven para organizar el código, los paquetes sirven para
organizar los módulos. Los paquetes son tipos especiales de módulos
(ambos son de tipo module) que permiten agrupar módulos relacio-
nados. Mientras los módulos se corresponden a nivel físico con los
archivos, los paquetes se representan mediante directorios.
import paq.subpaq.modulo
paq.subpaq.modulo.func()
76
Entrada/Salida Y
Ficheros
Entrada estándar
La forma más sencilla de obtener información por parte del usuario
es mediante la función raw_input. Esta función toma como paráme-
tro una cadena a usar como prompt (es decir, como texto a mostrar al
usuario pidiendo la entrada) y devuelve una cadena con los caracteres
introducidos por el usuario hasta que pulsó la tecla Enter. Veamos un
pequeño ejemplo:
try:
edad = raw_input(“Cuantos anyos tienes? “)
77
Python para todos
import sys
Existen módulos, como optparse, que facilitan el trabajo con los argu-
mentos de la línea de comandos, pero explicar su uso queda fuera del
objetivo de este capítulo.
Salida estándar
La forma más sencilla de mostrar algo en la salida estándar es median-
te el uso de la sentencia print, como hemos visto multitud de veces en
78
Entrada/Salida. Ficheros
print “Hola\n\n\tmundo”
79
Python para todos
Esto se diferencia del uso del operador + para concatenar las cadenas
en que al utilizar las comas print introduce automáticamente un espa-
cio para separar cada una de las cadenas. Este no es el caso al utilizar
el operador +, ya que lo que le llega a print es un solo argumento: una
cadena ya concatenada.
80
Entrada/Salida. Ficheros
Especificador Formato
%s Cadena
%d Entero
%o Octal
%x Hexadecimal
%f Real
81
Python para todos
Archivos
Los ficheros en Python son objetos de tipo file creados mediante la
función open (abrir). Esta función toma como parámetros una cadena
con la ruta al fichero a abrir, que puede ser relativa o absoluta; una
cadena opcional indicando el modo de acceso (si no se especifica se
accede en modo lectura) y, por último, un entero opcional para especi-
ficar un tamaño de buffer distinto del utilizado por defecto.
f = open(“archivo.txt”, “w”)
Lectura de archivos
82
Entrada/Salida. Ficheros
completo = f.read()
parte = f2.read(512)
El método readline sirve para leer las líneas del fichero una por una.
Es decir, cada vez que se llama a este método, se devuelve el conteni-
do del archivo desde el puntero hasta que se encuentra un carácter de
nueva línea, incluyendo este carácter.
while True:
linea = f.readline()
if not linea: break
print linea
Por último, readlines, funciona leyendo todas las líneas del archivo y
devolviendo una lista con las líneas leídas.
Escritura de archivos
Para la escritura de archivos se utilizan los método write y writelines.
Mientras el primero funciona escribiendo en el archivo una cadena de
texto que toma como parámetro, el segundo toma como parámetro una
lista de cadenas de texto indicando las líneas que queremos escribir en
el fichero.
Para esto se utiliza el método seek que toma como parámetro un nú-
83
Python para todos
84
Expresiones
Regulares
dir *.exe
‘*.exe’ sería una “expresión regular” que describiría todas las cadenas
de caracteres que empiezan con cualquier cosa seguida de ‘.exe’, es
decir, todos los archivos exe.
Patrones
La expresión regular más sencilla consiste en una cadena simple, que
85
Python para todos
describe un conjunto compuesto tan solo por esa misma cadena. Por
ejemplo, veamos cómo la cadena “python” coincide con la expresión
regular “python” usando la función match:
import re
if re.match(“python”, “python”):
print “cierto”
re.match(“.ython”, “python”)
re.match(“.ython”, “jython”)
re.match(“...\.”, “abc.”)
Si necesitáramos una expresión que sólo resultara cierta para las cade-
nas “python”, “jython” y “cython” y ninguna otra, podríamos utilizar
el carácter ‘|’ para expresar alternativa escribiendo los tres subpatro-
nes completos:
re.match(“python|jython|cython”, “python”)
o bien tan solo la parte que pueda cambiar, encerrada entre paréntesis,
formando lo que se conoce como un grupo. Los grupos tienen una
gran importancia a la hora de trabajar con expresiones regulares y este
no es su único uso, como veremos en la siguiente sección.
86
Expresiones regulares
re.match(“(p|j|c)ython”, “python”)
Otra opción consistiría en encerrar los caracteres ‘p’, ‘j’ y ‘c’ entre
corchetes para formar una clase de caracteres, indicando que en esa po-
sición puede colocarse cualquiera de los caracteres de la clase.
re.match(“[pjc]ython”, “python”)
re.match(“python[0-9]”, “python0”)
re.match(“python[0-9a-zA-Z]”, “pythonp”)
re.match(“python[.,]”, “python.”)
y no
re.match(“python[\.,]”, “python.”)
re.match(“python[^0-9a-z]”, “python+”)
Finalmente las llaves sirven para indicar el número de veces exacto que
puede aparecer el carácter de la izquierda, o bien un rango de veces que
puede aparecer. Por ejemplo {3} indicaría que tiene que aparecer exac-
tamente 3 veces, {3,8} indicaría que tiene que aparecer de 3 a 8 veces,
88
Expresiones regulares
Usando el módulo re
Ya hemos visto por encima cómo se utiliza la función match del módu-
lo re para comprobar si una cadena se ajusta a un determinado patrón.
El primer parámetro de la función es la expresión regular, el segundo,
la cadena a comprobar y existe un tercer parámetro opcional que con-
tiene distintos flags que se pueden utilizar para modificar el comporta-
miento de las expresiones regulares.
89
Python para todos
El método groups, por su parte, devuelve una lista con todos los gru-
pos, exceptuando el grupo 0, que se omite.
91
Sockets
socket_s = socket.socket()
socket_s.bind((“localhost”, 9999))
Por último utilizamos listen para hacer que el socket acepte conexio-
nes entrantes y accept para comenzar a escuchar. El método listen
requiere de un parámetro que indica el número de conexiones máximas
que queremos aceptar; evidentemente, este valor debe ser al menos 1.
socket_s.listen(10)
Una vez que tenemos este objeto socket podemos comunicarnos con
el cliente a través suyo, mediante los métodos recv y send (o recvfrom
y sendfrom en UDP) que permiten recibir o enviar mensajes respec-
tivamente. El método send toma como parámetros los datos a enviar,
mientras que el método recv toma como parámetro el número máxi-
mo de bytes a aceptar.
recibido = socket_c.recv(1024)
print “Recibido: “, recibio
socket_c.send(recibido)
93
Python para todos
Crear un cliente es aún más sencillo. Solo tenemos que crear el objeto
socket, utilizar el método connect para conectarnos al servidor y uti-
lizar los métodos send y recv que vimos anteriormente. El argumento
de connect es una tupla con host y puerto, exactamente igual que bind.
socket_c = socket.socket()
socket_c.connect((“localhost”, 9999))
socket_c.send(“hola”)
import socket
s = socket.socket()
s.bind((“localhost”, 9999))
s.listen(1)
while True:
recibido = sc.recv(1024)
if recibido == “quit”:
break
print “Recibido:”, recibido
sc.send(recibido)
print “adios”
sc.close()
s.close()
import socket
s = socket.socket()
s.connect((“localhost”, 9999))
94
Sockets
while True:
mensaje = raw_input(“> “)
s.send(mensaje)
mensaje == “quit”:
break
print “adios”
s.close()
95
Interactuar con
webs
import urllib2
96
Interactuar con webs
try:
f = urllib2.urlopen(“http://www.python.org”)
print f.read()
f.close()
except HTTPError, e:
print “Ocurrió un error”
print e.code
except URLError, e:
print “Ocurrió un error”
print e.reason
‘password=contrase%A4a&usuario=manuel’
leídos.
f = urllib2.urlopen(“http://ejemplo.com/login” +
“?” + params)
HTTPBasicAuthHandler:
aut_h = urllib2.HTTPBasicAuthHandler()
aut_h.add_password(“realm”, “host”, “usuario”, “password”)
opener = urllib2.build_opener(aut_h)
urllib2.install_opener(opener)
f = urllib2.urlopen(“http://www.python.org”)
opener = urllib2.build_opener(proxy_h)
urllib2.install_opener(opener)
f = urllib2.urlopen(“http://www.python.org”)
Para que se guarden las cookies que manda HTTP utilizamos el ma-
nejador HTTPCookieProcessor.
cookie_h = urllib2.HTTPCookieProcessor()
opener = urllib2.build_opener(cookie_h)
urllib2.install_opener(opener)
f = urllib2.urlopen(“http://www.python.org”)
Para leer las cookies mandadas basta crear un objeto iterable a partir
del CookieJar (también podríamos buscar las cabeceras correspondien-
tes, pero este sistema es más claro y sencillo):
100
Interactuar con webs
cookie_j = cookielib.CookieJar()
cookie_h = urllib2.HTTPCookieProcessor(cookie_j)
opener = urllib2.build_opener(cookie_h)
opener.open(“http://www.python.org”)
101
Threads
102
Threads
El GIL
La ejecución de los threads en Python está controlada por el GIL
(Global Interpreter Lock) de forma que sólo un thread puede ejecutar-
se a la vez, independientemente del número de procesadores con el que
cuente la máquina. Esto posibilita que el escribir extensiones en C para
Python sea mucho más sencillo, pero tiene la desventaja de limitar mu-
cho el rendimiento, por lo que a pesar de todo, en Python, en ocasiones
nos puede interesar más utilizar procesos que threads, que no sufren de
esta limitación.
Threads en Python
El trabajo con threads se lleva a cabo en Python mediante el módulo
thread. Este módulo es opcional y dependiente de la plataforma, y
puede ser necesario, aunque no es común, recompilar el intérprete para
añadir el soporte de threads.
import threading
class MiThread(threading.Thread):
def __init__(self, num):
threading.Thread.__init__(self)
self.num = num
def run(self):
print “Soy el hilo”, self.num
Para que el thread comience a ejecutar su código basta con crear una
instancia de la clase que acabamos de definir y llamar a su método
start. El código del hilo principal y el del que acabamos de crear se
ejecutarán de forma concurrente.
104
Threads
t = MiThread(i)
t.start()
t.join()
import threading
def imprime(num):
print “Soy el hilo”, num
105
Python para todos
Por último tenemos en el módulo threading una clase Timer que he-
reda de Thread y cuya utilidad es la de ejecutar el código de su método
run después de un periodo de tiempo indicado como parámetro en
su constructor. También incluye un método cancel mediante el que
cancelar la ejecución antes de que termine el periodo de espera.
Sincronización
Uno de los mayores problemas a los que tenemos que enfrentarnos al
utilizar threads es la necesidad de sincronizar el acceso a ciertos recur-
sos por parte de los threads. Entre los mecanismos de sincronización
que tenemos disponibles en el módulo threading se encuentran los
locks, locks reentrantes, semáforos, condiciones y eventos.
106
Threads
lista = []
lock = threading.Lock()
def anyadir(obj):
lock.acquire()
lista.append(obj)
lock.release()
def obtener():
lock.acquire()
obj = lista.pop()
lock.release()
return obj
107
Python para todos
semaforo = threading.Semaphore(4)
def descargar(url):
semaforo.acquire()
urllib.urlretrieve(url)
semaforo.release()
Las condiciones (clase Condition) son de utilidad para hacer que los
threads sólo puedan entrar en la sección crítica de darse una cierta
condición o evento. Para esto utilizan un Lock pasado como parámetro,
o crean un objeto RLock automaticamente si no se pasa ningún pará-
metro al constructor.
108
Threads
Tanto el thread que notifica como los que son notificados tienen que
terminar liberando el lock con release.
lista = []
cond = threading.Condition()
def consumir():
cond.acquire()
cond.wait()
obj = lista.pop()
cond.release()
return obj
def producir(obj):
cond.acquire()
lista.append(obj)
cond.notify()
cond.release()
Como vemos los eventos son muy similares a las condiciones, a excep-
ción de que se desbloquean todos los threads que esperaban el evento y
que no tenemos que llamar a acquire y release.
class MiThread(threading.Thread):
def __init__(self, evento):
threading.Thread.__init__(self)
self.evento = evento
def run(self):
print self.getName(), “esperando al evento”
self.evento.wait()
print self.getName(), “termina la espera”
evento = threading.Event()
t1 = MiThread(evento)
t1.start()
t2 = MiThread(evento)
t2.start()
# Esperamos un poco
time.sleep(5)
evento.set()
Por último, un pequeño extra. Si sois usuarios de Java sin duda estaréis
echando en falta una palabra clave syncronized para hacer que sólo
un thread pueda acceder al método sobre el que se utiliza a la vez. Una
construcción común es el uso de un decorador para implementar esta
funcionalidad usando un Lock. Sería algo así:
def synchronized(lock):
def dec(f):
def func_dec(*args, **kwargs):
lock.acquire()
try:
return f(*args, **kwargs)
finally:
lock.release()
return func_dec
return dec
class MyThread(threading.Thread):
@synchronized(mi_lock)
def run(self):
print “metodo sincronizado”
110
Threads
datos_locales = threading.local()
datos_locales.mi_var = “hola”
print datos_locales.mi_var
local = threading.local()
def f():
print local.var
local.var = “hola”
t = threading.Thread(target=f)
print local.var
t.start()
t.join()
Compartir información
Para compartir información entre los threads de forma sencilla po-
demos utilizar la clase Queue.Queue, que implementa una cola (una
estructura de datos de tipo FIFO) con soporte multihilo. Esta clase
utiliza las primitivas de threading para ahorrarnos tener que sincroni-
zar el acceso a los datos nosotros mismos.
111
Python para todos
q = Queue.Queue()
class MiThread(threading.Thread):
def __init__(self, q):
self.q = q
threading.Thread.__init__(self)
def run(self):
while True:
try:
obj = q.get(False)
except Queue.Empty:
print “Fin”
break
print obj
for i in range(10):
q.put(i)
t = MiThread(q)
t.start()
t.join()
112
Serialización de
objetos
En Python tenemos varios módulos que nos facilitan esta tarea, como
marshal, pickle, cPickle y shelve.
marshal sólo permite serializar objetos simples (la mayoría de los tipos
incluidos por defecto en Python), y no proporciona ningún tipo de
mecanismo de seguridad ni comprobaciones frente a datos corruptos o
mal formateados. Es más, el formato utilizado para guardar el bytecode
(y por tanto el formato utilizado para guardar los objetos con marshal)
puede cambiar entre versiones, por lo que no es adecuado para almace-
nar datos de larga duración.
try:
import cPickle as pickle
except ImportError:
import pickle
try:
import cPickle as pickle
except ImportError:
import pickle
pickle.dump(animales, fichero)
fichero.close()
try:
import cPickle as pickle
except ImportError:
import pickle
pickle.dump(animales, fichero, 2)
fichero.close()
try:
import cPickle as pickle
except ImportError:
import pickle
pickle.dump(animales, fichero)
fichero.close()
fichero = file(“datos.dat”)
animales2 = pickle.load(fichero)
print animales2
pickle.dump(animales, fichero)
pickle.dump(lenguajes, fichero)
fichero = file(“datos.dat”)
animales2 = pickle.load(fichero)
lenguajes2 = pickle.load(fichero)
print animales2
print lenguajes2
115
Python para todos
import shelve
shelf = shelve.open(“datos.dat”)
shelf[“primera”] = animales
shelf[“segunda”] = lenguajes
print shelf[“segunda”]
shelf.close()
116
Bases de Datos
DB API
Existen cientos de bases de datos en el mercado, tanto comerciales
como gratuitas. También existen decenas de módulos distintos para
trabajar con dichas bases de datos en Python, lo que significa decenas
de APIs distintas por aprender.
En Python, como en otros lenguajes como Java con JDBC, existe una
propuesta de API estándar para el manejo de bases de datos, de forma
que el código sea prácticamente igual independientemente de la base
de datos que estemos utilizando por debajo. Esta especificación recibe
el nombre de Python Database API o DB-API y se recoge en el PEP
249 (http://www.python.org/dev/peps/pep-0249/).
117
Python para todos
Variables globales
Antes de comenzar a trabajar con sqlite3, vamos a consultar algunos
datos interesantes sobre el módulo. Todos los drivers compatibles con
DB-API 2.0 deben tener 3 variables globales que los describen. A
saber:
Excepciones
A continuación podéis encontrar la jerarquía de excepciones que deben
proporcionar los módulos, junto con una pequeña descripción de cada
excepción, a modo de referencia.
StandardError
|__Warning
|__Error
|__InterfaceError
|__DatabaseError
|__DataError
|__OperationalError
|__IntegrityError
|__InternalError
|__ProgrammingError
|__NotSupportedError
119
Python para todos
c = bbdd.cursor()
121
Python para todos
bbdd.rollback()
bbdd = dbapi.connect(“bbdd.dat”)
cursor = bbdd.cursor()
bbdd.commit()
122
Bases de datos
123
Python para todos
cursor.close()
bbdd.close()
Tipos SQL
En ocasiones podemos necesitar trabajar con tipos de SQL, y almace-
nar, por ejemplo, fechas u horas usando Date y Time y no con cadenas.
La API de bases de datos de Python incluye una serie de constructores
a utilizar para crear estos tipos. Estos son:
Otras opciones
Por supuesto no estamos obligados a utilizar DB-API, ni bases de
datos relacionales. En Python existen módulos para trabajar con bases
de datos orientadas a objetos, como ZODB (Zope Object Database)
y motores para mapeo objeto-relacional (ORM) como SQLAlchemy,
SQLObject o Storm.
124
Documentación
Docstrings
En capítulos anteriores ya comentamos en varias ocasiones que todos
los objetos cuentan con una variable especial __doc__ mediante la que
indicar el propósito y uso del objeto. Estos son los llamados docstrings
o cadenas de documentación.
def haz_algo(arg):
“””Este es el docstring de la funcion.”””
print arg
print haz_algo.__doc__
print haz_algo.__doc__
>>> help(haz_algo)
Help on function haz_algo in module __main__:
haz_algo(arg)
125
Python para todos
Pydoc
La función help, que comentamos brevemente con anterioridad,
utiliza el módulo pydoc para generar la documentación de un objeto a
partir de su docstring y los docstrings de sus miembros. Este módulo,
incluido por defecto con Python desde la versión 2.1, se puede impor-
tar en nuestro código Python y utilizarse programaticamente, o bien se
puede utilizar como una herramienta de línea de comandos que sería el
equivalente a la aplicación Javadoc del mundo Java.
pydoc.py -k xml
pydoc.py -p puerto
126
Documentación
Epydoc y reStructuredText
El problema de pydoc es que es muy simple, y no permite añadir
semántica o modificar estilos de la documentación. No podemos, por
ejemplo, indicar que en una línea en concreto de entre las líneas de
documentación de la función describe un parámetro de la función o
mostrar un cierto término en cursiva.
Vamos a crear un pequeño módulo con un par de clases para ver pri-
mero el resultado de utilizar epydoc con docstrings de texto plano, sin
ningún tipo de marcado especial.
class Persona:
“””Mi clase de ejemplo.”””
def __init__(self, nombre):
“””Inicializador de la clase Persona.”””
self.nombre = nombre
self.mostrar_nombre()
def mostrar_nombre(self):
“””Imprime el nombre de la persona”””
print “Esta es la persona %s” % self.nombre
class Empleado(Persona):
“””Subclase de Persona.”””
pass
if __name__ == “__main__”:
raul = Persona(“Raul”)
128
Documentación
epydoc ejemplo.py
o bien
129
Python para todos
Título
======
Subtitulo
—————————
Título
Subtitulo
Para crear una lista no ordenada se empieza cada línea con el caracter
‘*’, ‘-’ o ‘+’:
* Python
* C
* Java
• Python
• C
• Java
Para crear una lista numerada se empieza la línea con el número se-
130
Documentación
1. Python
2. C
3. Java
1. Python
2. C
3. Java
Funciones y métodos
:param p: Un parámetro Describe el parámetro p.
:type p: str Especifica el tipo esperado para el
parámetro p.
:return: True si son Valor de retorno.
iguales
:rtype: str Tipo del valor de retorno.
:keyword p: Un paráme- Descripción del parámetro con
tro valor por defecto y nombre p.
:raise e: Si el paráme- Describe las circunstancias para
tro es cero las que se lanza la excepción e.
Variables
:ivar v: Una variable Descripción de la instancia v.
:cvar v: Una variable Descripción de la variable estática
de clase v.
:var v: Una variable Descripción de la variable v del
módulo.
131
Python para todos
Notas
:note: Una nota Una nota sobre el objeto.
:attention: Importante Una nota importante sobre el
objeto.
:bug: No funciona para Descripción de un error en el
el valor 0 objeto.
:warning: Cuidado con Una advertencia acerca de un
el valor 0 objeto.
:see: Ver ‘Python para Para indicar información relacio-
todos’ nada.
Estado
:version: 1.0 Versión actual del objeto.
:change: Versión ini- Listado de cambios.
cial
:todo: Internacionali- Un cambio planeado para el
zación objeto.
:status: Versión esta- Estado del objeto.
ble
Autoría
:author: Raul Gonzalez Autor o autores del objeto.
:organization: Mundo Organización que creó o mantiene
geek el objeto.
:license: GPL Licencia del objeto.
:contact: zootropo en Información de contacto del autor.
gmail
132
Documentación
__docformat__ = “restructuredtext”
class Persona:
“””Modela una persona.”””
def __init__(self, nombre, edad):
“””Inicializador de la clase `Persona`.
:param nombre: Nombre de la persona.
:param edad: Edad de la persona”””
self.nombre = nombre
self.edad = edad
self.mostrar_nombre()
def mostrar_nombre(self):
“””Imprime el nombre de la persona”””
print “Esta es la persona %s” % self.nombre
class Empleado(Persona):
“””Subclase de `Persona` correspondiente a las personas
que trabajan para la organizacion.
:todo: Escribir implementacion.”””
pass
if __name__ == “__main__”:
juan = Persona(“Juan”, 26)
class Persona:
“””Modela una persona.”””
def __init__(self, nombre, edad):
“””Inicializador de la clase `Persona`.
:Parameters:
- `nombre`: Nombre de la persona.
- `edad`: Edad de la persona.
“””
self.nombre = nombre
self.edad = edad
self.mostrar_nombre()
133
Python para todos
Otros campos que admiten listas son :Exceptions: para indicar varias
excepciones (:except:), :Variables: para comentar varias variables
(:var:) o :Ivariables: para comentar varias instancias (:ivar:).
134
Pruebas
Doctest
Como es de suponer por el nombre del módulo, doctest permite
combinar las pruebas con la documentación. Esta idea de utilizar las
pruebas unitarias para probar el código y también a modo de docu-
mentación permite realizar pruebas de forma muy sencilla, propicia el
que las pruebas se mantengan actualizadas, y sirve a modo de ejemplo
de uso del código y como ayuda para entender su propósito.
135
Python para todos
def cuadrados(lista):
“””Calcula el cuadrado de los numeros de una lista”””
def cuadrados(lista):
“””Calcula el cuadrado de los numeros de una lista
>>> l = [0, 1, 2, 3]
>>> cuadrados(l)
[0, 1, 4, 9]
“””
def cuadrados(lista):
“””Calcula el cuadrado de los numeros de una lista
>>> l = [0, 1, 2, 3]
>>> cuadrados(l)
[0, 1, 4, 9]
“””
def _test():
import doctest
doctest.testmod()
136
Pruebas
if __name__ == “__main__”:
_test()
Trying:
l = [0, 1, 2, 3]
Expecting nothing
ok
Trying:
cuadrados(l)
Expecting:
[0, 1, 4, 9]
ok
2 items had no tests:
__main__
__main__._test
1 items passed all tests:
2 tests in __main__.cuadrados
2 tests in 3 items.
2 passed and 0 failed.
Test passed.
def cuadrados(lista):
“””Calcula el cuadrado de los numeros de una lista
>>> l = [0, 1, 2, 3]
>>> cuadrados(l)
[0, 1, 4, 9]
“””
def _test():
137
Python para todos
import doctest
doctest.testmod()
if __name__ == “__main__”:
_test()
*********************************************************
File “ejemplo.py”, line 5, in __main__.cuadrados
Failed example:
cuadrados(l)
Expected:
[0, 1, 4, 9]
Got:
[0, 2, 4, 6]
*********************************************************
1 items had failures:
1 of 2 in __main__.cuadrados
***Test Failed*** 1 failures.
Veamos por último cómo utilizar sentencias anidadas para hacer cosas
un poco más complicadas con doctest. En el ejemplo siguiente nuestra
función calcula el cuadrado de un único número pasado como pará-
metro, y diseñamos una prueba que compruebe que el resultado es el
adecuado para varias llamadas con distintos valores. Las sentencias
anidadas comienzan con “...” en lugar de “>>>”:
def cuadrado(num):
“””Calcula el cuadrado de un numero.
>>> l = [0, 1, 2, 3]
>>> for n in l:
... cuadrado(n)
[0, 1, 4, 9]
“””
return num ** 2
def _test():
import doctest
doctest.testmod()
138
Pruebas
if __name__ == “__main__”:
_test()
unittest / PyUnit
unittest, también llamado PyUnit, forma parte de una familia de
herramientas conocida colectivamente como xUnit, un conjunto de
frameworks basados en el software SUnit para Smalltalk, creado por
Kent Beck, uno de los padres de la eXtreme Programming. Otros
ejemplos de herramientas que forman parte de esta familia son JUnit
para Java, creada por el propio Kent Beck junto a Erich Gamma, o
NUnit, para .NET.
Para ejecutar las pruebas, basta llamar a la función main() del módulo,
con lo que se ejecutarán todos los métodos cuyo nombre comience con
test, en orden alfanumérico. Al ejecutar cada una de las pruebas el
resultado puede ser:
import unittest
class EjemploPruebas(unittest.TestCase):
def test(self):
pass
if __name__ == “__main__”:
unittest.main()
139
Python para todos
import unittest
class EjemploPruebas(unittest.TestCase):
def test(self):
raise AssertionError()
if __name__ == “__main__”:
unittest.main()
Nada nos impide utilizar cláusulas if para evaluar las condiciones que
nos interesen y lanzar una excepción de tipo AssertionError cuando
no sea así, pero la clase TestCase cuenta con varios métodos que nos
pueden facilitar la tarea de realizar comprobaciones sencillas. Son los
siguientes:
140
Pruebas
import unittest
def cuadrado(num):
“””Calcula el cuadrado de un numero.”””
return num ** 2
class EjemploPruebas(unittest.TestCase):
def test(self):
l = [0, 1, 2, 3]
r = [cuadrado(n) for n in l]
self.assertEqual(r, [0, 1, 4, 9])
if __name__ == “__main__”:
unittest.main()
141
Python para todos
class EjemploFixture(unittest.TestCase):
def setUp(self):
print “Preparando contexto”
self.lista = [0, 1, 2, 3]
def test(self):
print “Ejecutando prueba”
r = [cuadrado(n) for n in self.lista]
self.assertEqual(r, [0, 1, 4, 9])
def tearDown(self):
print “Desconstruyendo contexto”
del self.lista
142
Distribuir
aplicaciones
Python
distutils
Todo programa distribuido con distutils contiene un script llama-
do por convención setup.py, que se encarga de instalar la aplicación
llamando a la función setup de distutils.core. Esta función tiene
montones de argumentos, que controlan, entre otras cosas, cómo insta-
lar la aplicación.
143
Python para todos
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”]
)
Si hemos escrito otros módulos para ser utilizados por el script prin-
cipal, estos se indican mediante el parámetro py_modules. Por ejemplo,
supongamos que la aplicación consiste en un script principal ejemplo.
py, y un módulo de apoyo apoyo.py:
144
Distribuir aplicaciones Python
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”],
py_modules=[“apoyo”]
)
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”],
packages=[“gui”, “bbdd”]
)
Al ejecutar el comando
a los usuarios. Para crear archivos con el código fuente se utiliza la op-
ción sdist de setup.py, que crea por defecto un archivo tar.gz en Unix
y un zip en Windows.
bztar .tar.bz2
gztar .tar.gz
tar .tar
zip .zip
ztar .tar.Z
rpm RPM
gztar .tar.gz
bztar .tar.bz2
ztar .tar.Z
tar .tar
wininst Instalador Windows
zip .zip
146
Distribuir aplicaciones Python
setuptools
setuptools extediende distutils añadiendo una serie de funcionalidades
muy interesantes: introduce un nuevo formato de archivo para distri-
bución de aplicaciones Python llamado egg, se encarga de buscar todos
los paquetes que deben instalarse y añadir las posibles dependencias,
permite instalar paquetes de PyPI con un solo comando, etc.
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”],
)
147
Python para todos
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”],
)
easy_install docutils
Searching for docutils
Reading http://pypi.python.org/simple/docutils/
Reading http://docutils.sourceforge.net/
Best match: docutils 0.5
Downloading http://prdownloads.sourceforge.net/docutils/
docutils-0.5.tar.gz?download
Processing docutils-0.5.tar.gz
Running docutils-0.5/setup.py -q bdist_egg --dist-dir /tmp/
easy_install-wUAyUZ/docutils-0.5/egg-dist-tmp-kWkkkv
“optparse” module already present; ignoring extras/optparse.
py.
“textwrap” module already present; ignoring extras/textwrap.
py.
zip_safe flag not set; analyzing archive contents…
148
Distribuir aplicaciones Python
149
Python para todos
4. quit
Your selection [default 1]: 1
Username: zootropo
Password:
Server response (200): OK
I can store your PyPI login so future submissions will be
faster.
(the login will be stored in /home/zootropo/.pypirc)
Save your login (y/N)?y
easy_install mi-paquete
Eggs
Los eggs (huevo en inglés) son archivos de extensión .egg mediante los
que distribuir aplicaciones en Python. Serían algo así como el equiva-
lente a los archivos .jar del mundo Java. Son multiplataforma, permi-
ten manejar dependencias, y permiten instalar distintas versiones del
mismo paquete.
150
Distribuir aplicaciones Python
easy_install mi-aplicacion.egg
easy_install http://mundogeek.net/mi-aplicacion.egg
install_requires = [“apoyo”]
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”],
packages = find_packages()
)
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”],
console=[“ejemplo.py”]
)
Con esto py2exe generará un directorio build, con las librerías com-
piladas, y un directorio dist, con los archivos que conforman nuestra
aplicación.
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”],
console=[“ejemplo.py”],
options={“py2exe”: {“bundle_files”: 1}}
)
setup(name=”Aplicacion de ejemplo”,
version=”0.1”,
description=”Ejemplo del funcionamiento de distutils”,
author=”Raul Gonzalez”,
author_email=”zootropo en gmail”,
url=”http://mundogeek.net/tutorial-python/”,
license=”GPL”,
scripts=[“ejemplo.py”],
console=[“ejemplo.py”],
options={“py2exe”: {“bundle_files”: 1}},
zipfile=None
)
154
Índice
Símbolos
__call__ 105
__cmp__ 51
__del__ 51
__doc__ 75, 125
__init__ 43
__len__ 51
__main__ 74
__name__ 74
__new__ 51
__str__ 51
A
archivos 82
atributos 42
B
bases de datos 117
bool 22
break 33
C
cadenas, métodos 54
candados 106
clases 42
clases de nuevo estilo 50
class 43
close 82
cola multihilo 111
colecciones
diccionarios 27
listas 24 155
tuplas 26
comentarios 9
compile 91
comprensión de listas 61
condiciones, sincronización 108
continue 33
cookies 100
count 45
cPickle 114
D
db api 117
decoradores 63
def 36
diccionario, métodos 53
distutils 143
docstring 36
docstrings 125
doctest 135
docutils 127
E
eggs 150
elif 31
else 30
encapsulación 48
env 127
epydoc 109
eventos 65
excepciones 66
except 85
F
False 22
ficheros 82
file 82
filter 59
finally 67
findall 90
float 17
for ... in 34
fork 102
from ... import 73
156
fuertemente tipado 8
funciones 36
funciones de orden superior 57
funciones lambda 60
G
generadores 62
GIL 103
Global Interpreter Lock 103
H
hashbang 13
help 36
herencia 45
herencia múltiple 46
hilos 102
I
if 29
import 72
input 78
int 10. Véase aquí enteros
iPython 39
J
Jython 9
K
Komodo 11
L
lambda 60
lenguaje compilado 7
lenguaje de script 7
lenguaje interpretado 7
lenguaje semi interpretado 7
listas, métodos 55
locks 106
M
map 59 157
marshal 113
marshalling 113
match 86
métodos 42
module 75
módulos 72
mutex 106
N
name mangling 49
None 36
O
objetos 42
open 82
operaciones relacionales 22
operadores a nivel de bit 20
operadores aritméticos 18
operadores lógicos 22
orientación a objetos 8
P
paquetes 75
parámetros, funciones 37
parámetros por línea de comando 78
parámetros, valores por defecto 38
particionado 25
paso por referencia 39
paso por valor 39
patrones (expresiones regulares) 85
pickle 113
polimorfismo 47
print 78
procesos 102
programación funcional 57
programación orientada a objetos 42
propiedades 49
pruebas 135
py2exe 152
PyDEV 11
pydoc 126
PyPI 148
PyPy 9
158
Python
definición 9
instalación 8
ventajas 74
PYTHONPATH 139
R
raise 67
raw, cadena 21
raw_input 77
read 83
readline 83
readlines 83
reduce 60
reStructuredText 127
return 40
S
search 90
seek 83
self 44
semáforos 107
serialización 113
setuptools 147
sharpbang 13
shebang 13
shelve 116
sincronización 106
slicing 25
sockets 92
split 91
sub 91
subclase 45
superclase 45
sys.argv 78
T
tell 84
test fixture 141
tests 135
threading 104
threads 102
tipado dinámico 7
159
tipado fuerte 8
tipos básicos 15
booleanos 22
cadenas 21
números
complejos 16
enteros 17
reales 22
True 66
try 15
U
unittest 139
upper 45
urllib 96
urllib2 96
V
valores inmutables 40
valores mutables 40
W
while 32
Wing IDE 11
write 83
writelines 83
Y
yield 62
160