Subsecciones


7. Entrada y salida

Hay varios modos de presentar la salida de un programa; se pueden imprimir datos en un modo legible a los humanos o escribirlos en un fichero para uso posterior. Este cap�tulo explora algunas de las posibilidades.


7.1 Formato de salida mejorado

Hasta ahora hemos encontrado dos modos de escribir valores: las sentencias de expresi�n y la sentencia print Hay un tercer modo, utilizar el m�todo write() de los objetos fichero, donde se puede acceder al fichero de salida est�ndar es accesible mediante sys.stdout. Consulta la Referencia de las bibliotecas si deseas obtener informaci�n sobre el tema.

A menudo, querr�s tener m�s control sobre el formato de la salida que escribir valores separados por espacios. Hay dos modos de dar formato a la salida: El primer modo es gestionar t� mismo las cadenas. Mediante corte y empalme de cadenas se puede generar cualquier formato. El m�dulo est�ndar string contiene operaciones �tiles para ajustar cadenas a un ancho de columna dado. Esto se discutir� en breve. El segundo modo es utilizar el operador % con una cadena como argumento izquierdo. El operador % interpreta el argumento izquierdo como una cadena de formato estilo sprintf() de C, que ha de ser aplicado sobre el argumento derecho para devolver la cadena resultante del formato.

Queda una cuesti�n, por supuesto: �C�mo convertir valores a cadenas? Afortunadamente, Python tiene un modo de convertir cualquier valor a cadena: pasarle la funci�n repr() o, simplemente, escribir el valor entre comillas simples invertidas (``). He aqu� algunos ejemplos:

>>> x = 10 * 3.14
>>> y = 200*200
>>> s = 'El valor de "x" es ' + `x` + ' e "y" vale ' + `y` + '...'
>>> print s
El valor de "x" es 31.4 e "y" vale 40000...
>>> # Las comillas invertidas funcionan sobre otros tipos, adem�s de los n�meros:
... p = [x, y]
>>> ps = repr(p)
>>> ps
'[31.4, 40000]'
>>> # Convertir a cadena a�ade a las cadenas comillas y barras invertidas:
... hola = 'hola, mundo\n'
>>> cadhola = `hola`
>>> print cadhola
'hola, mundo\012'
>>> # El argumento de las comillas invertidas puede ser una tupla:
... `x, y, ('fiambre', 'huevos')`
"(31.4, 40000, ('fiambre', 'huevos'))"

He aqu� dos modos de escribir una tabla de cuadrados y cubos:

>>> import string
>>> for x in range(1, 11):
...     print string.rjust(`x`, 2), string.rjust(`x*x`, 3),
...     # Observa la coma final de la l�nea anterior
...     print string.rjust(`x*x*x`, 4)
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000
>>> for x in range(1,11):
...     print '%2d %3d %4d' % (x, x*x, x*x*x)
... 
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

Observa que se ha a�adido un espacio entre columnas por el modo en que funciona print: siempre a�ade un espacio entre sus argumentos.

Este ejemplo utiliza la funci�n string.rjust(), que ajusta a la derecha una cadena dada una anchura determinada, a�adiendo espacios a la izquierda. Existen las funciones relacionadas string.ljust() y string.center(). Estas funciones no escriben nada, s�lo devuelven una cadena nueva. Si la cadena de entrada es demasiado larga, no la recortan, sino que la devuelven sin cambios. Se embrollar� la salida, pero suele ser mejor que falsear los valores (si es preferible truncar la salida, siempre se puede agregar una operaci�n de corte, como "string.ljust(x,n)[0:n]").

Existe otra funci�n, string.zfill(), que rellena una cadena num�rica por la izquierda con ceros. Entiende de signos positivo y negativo:

>>> import string
>>> string.zfill('12', 5)
'00012'
>>> string.zfill('-3.14', 7)
'-003.14'
>>> string.zfill('3.14159265359', 5)
'3.14159265359'
Usar el operador % tiene este aspecto:

>>> import math
>>> print 'El valor de PI es aproximadamente %5.3f.' % math.pi
El valor de PI es aproximadamente 3.142.

Si hay m�s de un formato en la cadena, se ha de pasar una tupla como operando derecho, como aqu�:

>>> tabla = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for nombre, telef in tabla.items():
...     print '%-10s ==> %10d' % (nombre, telef)
... 
Jack       ==>       4098
Dcab       ==>       7678
Sjoerd     ==>       4127

La mayor�a de los formatos funcionan como en C y exigen que se pase el tipo correcto. Sin embargo, de no hacerlo as�, s�lo se causa una excepci�n y no un volcado de memoria (o error de protecci�n general). El formato %s es m�s relajado: Si el argumento correspondiente no es un objeto de cadena, se convierte a cadena mediante la funci�n interna str(). Es posible pasar * para indicar la precisi�n o anchura como argumento (entero) aparte. No se puede utilizar los formatos de C %n ni %p.

Si tienes una cadena de formato realmente larga que no deseas dividir, ser�a un detalle hacer referencia a las variables por su nombre, en vez de por su posici�n. Esto se logra con una extensi�n a los formatos de C, con el formato %(nombre)formato, por ejemplo:

>>> tabla = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % tabla
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Esto resulta particularmente pr�ctico en combinaci�n con la nueva funci�n interna vars(), que devuelve un diccionario que contiene todas las variables locales.


7.2 Lectura y escritura de ficheros

open() (abrir) devuelve un objeto fichero. Se suele usar con dos argumentos: "open(nombreFichero, modo)".

>>> f=open('/tmp/fichTrabajo', 'w')
>>> print f
<open file '/tmp/fichTrabajo', mode 'w' at 80a0960>

El primer argumento es una cadena que contiene el nombre del fichero. El segundo argumento es otra cadena que contiene caracteres que describen el modo en que se va a utilizar el fichero. El modo puede ser 'r', cuando s�lo se va a leer del fichero, 'w', si s�lo se va a escribir (y si existe un fichero del mismo nombre se borra) o 'a', que abre el fichero para a�adir datos. En el modo 'a', cualquier dato que se escriba en el fichero se a�adir� al final de los datos existentes. El argumento de modo es opcional. Se supone 'r' si se omite.

En Windows y Macintosh, al a�adir 'b' al modo, el fichero se abre en modo binario, por lo que existen modos como 'rb', 'wb' y 'r+b'. Windows distingue entre ficheros de texto y binarios: los caracteres de fin de l�nea de los ficheros de texto se alteran ligeramente de forma autom�tica al leer o escribir datos. Esta modificaci�n oculta no afecta en el caso de ficheros de texto ASCII, pero corrompe los ficheros de datos binarios, tales como ficheros JPEG o .EXE. Ten mucho cuidado de utilizar el modo binario al leer y escribir dichos ficheros (observa que el comportamiento preciso del modo de texto en Macintosh depende de la biblioteca C subyacente).


7.2.1 M�todos de los objetos fichero

El resto de los ejemplos de esta secci�n supondr�n que se ha creado previamente un objeto fichero denominado f.

Para leer el contenido de un fichero, llama a f.read(cantidad), que lee cierta cantidad de datos y los devuelve como cadena. cantidad es un argumento num�rico opcional. Si se omite o es negativo, se leer� y devolver� el contenido completo del fichero. Es problema tuyo si el fichero tiene un tama�o descomunal. Si se incluye el argumento y es positivo, se leen y devuelven como m�ximo cantidad bytes. Si se hab�a alcanzado el final de fichero, f.read() s�lo devuelve una cadena vac�a ("").

>>> f.read()
'Esto es el fichero completo.\012'
>>> f.read()
''

f.readline() lee una sola l�nea del fichero. Se deja un car�cter de cambio de l�nea (\n) al final de la cadena, que se omite s�lo en la �ltima l�nea, siempre que el fichero no termine en un salto de l�nea. De este modo se consigue que el valor devuelto no sea ambiguo. Si f.readline() devuelve una cadena vac�a, se ha alcanzado el final del fichero, mientras que una l�nea en blanco queda representada por '\n', una cadena que s�lo contiene un salto de l�nea.

>>> f.readline()
'La primera l�nea del fichero.\012'
>>> f.readline()
'La segunda l�nea del fichero\012'
>>> f.readline()
''

f.readlines() devuelve una lista que contiene todas las l�neas de datos del fichero. Si se llama con un par�metro opcional sizehint (estimaci�n de tama�o), lee los bytes indicados del fichero, sigue hasta completar una l�nea y devuelve la lista de l�neas. Se suele utilizar esto para leer un fichero grande de una manera eficaz por l�neas, pero sin tener que cargar en memoria el fichero entero. Todas las l�neas devueltas est�n completas

>>> f.readlines()
['La primera l�nea del fichero.\012', 'La segunda l�nea del fichero\012']

f.write(cadena) escribe el contenido de cadena al fichero y devuelve None.

>>> f.write('Probando, probando\n')

f.tell() devuelve un entero que indica la posici�n actual del objeto fichero dentro del fichero, medida en bytes desde el inicio del fichero. Para cambiar la posici�n del objeto fichero se usa "f.seek(desplazamiento, desde_d�nde)". La posici�n se calcula sumando desplazamiento a un punto de referencia, seleccionado por el argumento desde_d�nde. Un desde_d�nde cero mide desde el inicio del fichero, 1 utiliza la posici�n actual y 2 utiliza el final del fichero como punto de referencia. desde_d�nde se puede omitir, en cuyo caso se utiliza el valor cero y se mide desde el principio del fichero.

>>> f=open('/tmp/fichTrabajo', 'r+')
>>> f.write('0123456789abcdef')
>>> f.seek(5)     # Ir al 5� byte del fichero
>>> f.read(1)        
'5'
>>> f.seek(-3, 2) # Ir al 3er byte antes del final
>>> f.read(1)
'd'

Cuando termines de usar un fichero, llama a f.close() para cerrarlo y liberar los recursos del sistema que utilice el fichero. Tras llamar a f.close(), fracasar� cualquier intento de usar el objeto fichero.

>>> f.close()
>>> f.read()
Traceback (innermost last):
  File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file

Los ficheros objeto tienen m�s m�todos, como isatty() y truncate(), de uso menos frecuente. Consulta la Referencia de las bibliotecas si deseas ver una gu�a completa de los objetos fichero.


7.2.2 El m�dulo pickle

Es f�cil escribir y leer cadenas de un fichero. Los n�meros exigen un esfuerzo algo mayor, ya que el m�todo read() s�lo devuelve cadenas, que tendr�n que pasarse a una funci�n como string.atoi(), que toma una cadena como '123' y devuelve su valor num�rico 123. Sin embargo, cuando se quiere guardar tipos de datos m�s complejos, como listas, diccionarios o instancias de clases, las cosas se complican bastante.

Mejor que hacer que los usuarios est�n constantemente escribiendo y depurando c�digo para guardar tipos de datos complejos, Python proporciona un m�dulo est�ndar llamado pickle7.1. Es un m�dulo asombroso que toma casi cualquier objeto de Python (�hasta algunas formas de c�digo Python!) y lo convierte a una representaci�n de cadena. Este proceso se llama estibado. Reconstruir el objeto a partir de la representaci�n en forma de cadena se llama desestibado. Entre el estibado y el desestibado, la cadena que representa el objeto puede ser almacenada en un fichero, en memoria o transmitirse por una conexi�n de red a una m�quina remota.

Si partes de un objeto x y un objeto fichero f previamente abierto para escritura, el modo m�s sencillo de estibar el objeto s�lo tiene una l�nea de c�digo:

pickle.dump(x, f)

Para realizar el proceso inverso, si f es un objeto fichero abierto para escritura:

x = pickle.load(f)

Existen otras variaciones de este tema, que se utilizan para estibar muchos objetos o si no se quiere escribir los datos estibados a un fichero. Se puede consultar la documentaci�n completa de pickle en la Referencia de las bibliotecas.

pickle es el m�todo est�ndar para hacer que los objetos Python se puedan almacenar y reutilizar en otros programas o futuras ejecuciones del mismo programa. El t�rmino t�cnico que identifica esto es objeto persistente. Como pickle se utiliza tanto, muchos autores que escriben extensiones a Python tienen cuidado de asegurarse de que los nuevos tipos de datos, tales como matrices, se estiben y desestiben de la manera adecuada.



Notas al pie

...pickle7.1
N. del T. Pickle significa conservar en formol o encurtir, pero lo voy a traducir como estibar. Estibar es colocar los bultos en una nave para prepararla para el viaje, lo que se adapta bastante bien a la funci�n de pickle.

Ver Sobre este documento... para obtener informaci�n sobre sugerencias.