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.
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(), 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 modos de convertir cualquier valor a cadena:
pasarle la función repr() o str(). Las comillas inversas
(``
) equivalen a repr(), pero se desaconseja su uso.
La función str() debe devolver representaciones legibles por un humano de los valores, mientras repr() debe generar representaciones legibles por el intérprete (o harán saltar un SyntaxError si no hay una sintaxis equivalente). Para los objetos que no tienen una representación particular para consumo humano, str() devolverá el mismo valor que repr(). Muchos valores, tales como números o estructuras como listas y diccionarios, tienen la misma representación en cualquiera de las dos funciones. En concreto, las cadenas y los números en coma flotante tienen representaciones diferentes.
He aquí algunos ejemplos:
>>> s = 'Hola, mundo.' >>> str(s) 'Hola, mundo.' >>> repr(s) "'Hola, mundo.'" >>> str(0.1) '0.1' >>> repr(0.1) '0.10000000000000001' >>> x = 10 * 3.25 >>> y = 200 * 200 >>> s = 'El valor de x es ' + repr(x) + ', e y es ' + repr(y) + '...' >>> print s El valor de x es 32.5, e y es 40000... >>> # Aplicar repr() a una cadena le añade comillas y barras invertidas: ... hola = 'hola, mundo\n' >>> holas = repr(hola) >>> print holas 'hola, mundo\n' >>> # El argumento de repr() puede ser cualquier objeto de Python: ... repr((x, y, ('magro', 'huevos'))) "(32.5, 40000, ('magro', 'huevos'))" >>> # Las comillas invertidas son prácticas en las sesiones interactivas: ... `x, y, ('magro', 'huevos')` "(32.5, 40000, ('magro', 'huevos'))"
He aquí dos modos de escribir una tabla de cuadrados y cubos:
>>> for x in range(1, 11): ... print repr(x).rjust(2), repr(x*x).rjust(3), ... # Observa la coma final de la línea anterior ... print repr(x*x*x).rjust(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 el método rjust() de los objetos cadena, que ajusta a la derecha una cadena dada una anchura determinada, añadiendo espacios a la izquierda. Existen los métodos relacionados ljust() y center(). Estos métodos 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 "x.ljust(n)[:n]").
Existe otro método, zfill(), que rellena una cadena numérica por la izquierda con ceros. Entiende de signos positivo y negativo:
>>> import string >>> '12'.zfill(5) '00012' >>> '-3.14'.zfill(7) '-003.14' >>> '3.14159265359'.zfill(5) '3.14159265359'
%
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 %(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.
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).
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.\n' >>> 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.\n' >>> f.readline() 'La segunda línea del fichero\n' >>> 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.\n', 'La segunda línea del fichero\n']
f.write(cadena)
escribe el contenido de cadena al
fichero y devuelve None
.
>>> f.write('Probando, probando\n')
Para escribir algo diferente de una cadena, ha de ser convertido a cadena primero:
>>> valor = ('la respuesta', 42) >>> s = str(valor) >>> f.write(s)
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 6º 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 (most recent call 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.
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 int(),
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 de Python.
pickle es el método estándar para hacer que los objetos de 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.