Herramientas Informaticas

Mes: agosto 2012 Página 11 de 22

10.6. Enteros largos

Python proporciona un tipo llamado long int que puede manejar enteros de cualquier tamaño. Hay dos formas de crear un valor long int. Una es escribir un entero con una L mayúscula al final:

   1: >>> type(1L)

   2: <type 'long int'>

La otra es usar la función long para convertir un valor en long int. long acepta cualquier tipo numérico e incluso cadenas de dígitos:

   1: >>> long(1)

   2: 1L

   3: >>> long(3.9)

   4: 3L

   5: >>> long('57')

   6: 57L

Todas las operaciones matemáticas funcionan sobre los long ints, así que no tenemos que hacer mucho para adaptar fibonacci:

   1: >>> previous = {0:1L, 1:1L}

   2: >>> fibonacci(50)

   3: 20365011074L

Simplemente cambiando el contenido inicial de anteriores cambiamos el comportamiento de fibonacci. Los primeros dos números de la secuencia son long ints, así que todos los números subsiguientes lo serán también.

Como ejercicio, modifique factorial de forma que produzca un
long int como resultado.

10.7. Contar letras

En el capítulo 7 escribimos una función que contaba el numero de apariciones de una letra en una cadena. Una versión mas genérica de este problema es crear un histograma de las letras de la cadena, o sea, cuantas veces aparece cada letra.

Ese histograma podría ser útil para comprimir un archivo de texto. Como las diferentes letras aparecen con frecuencias distintas, podemos comprimir un archivo usando códigos cortos para las letras mas habituales y códigos mas largos para las que aparecen con menor frecuencia.

Los diccionarios facilitan una forma elegante de generar un histograma:

   1: >>> cuentaLetras = {}

   2: >>> for letra in "Mississippi":

   3: ... cuentaLetras[letra] = cuentaLetras.get (letra, 0) + 1

   4: ...

   5: >>> cuentaLetras

   6: {'M': 1, 's': 4, 'p': 2, 'i': 4}

   7: >>>

 

Inicialmente, tenemos un diccionario vacío. Para cada letra de la cadena, buscamos el recuento actual (posiblemente cero) y lo incrementamos. Al final, el diccionario contiene pares de letras y sus frecuencias.

Puede ser mas atractivo mostrar el histograma en orden alfabético. Podemos hacerlo con los métodos items y sort:

   1: >>> itemsLetras = cuentaLetras.items()

   2: >>> itemsLetras.sort()

   3: >>> print itemsLetras

   4: [('M', 1), ('i', 4), ('p', 2), ('s', 4)]

Ya había visto usted el metodo items, pero sort es el primer metodo aplicable a listas que hemos visto. Hay varios mas, como append, extend, y reverse.

Consulte la documentación de Python para ver los detalles.

10.8. Glosario

diccionario: Una colección de pares clave-valor que establece una correspondencia entre claves y valores. Las claves pueden ser de cualquier tipo inmutable, los valores pueden ser de cualquier tipo.

clave: Un valor que se usa para buscar una entrada en un diccionario.

par clave-valor: Uno de los elementos de un diccionario, también llamado ”asociacion”.

metodo: Un tipo de función al que se llama con una sintaxis diferente y al que se invoca sobre” un objeto.

invocar: Llamar a un metodo.

pista: Almacenamiento temporal de un valor pre-calculado para evitar cálculos redundantes.

desbordamiento: Un resultado numérico que es demasiado grande para representarse en formato numérico.

Capítulo 11 Archivos y excepciones

Cuando un programa se esta ejecutando, sus datos están en la memoria. Cuando un programa termina, o se apaga el computador, los datos de la memoria desaparecen. Para almacenar los datos de forma permanente debe usted ponerlos en
un archivo. Normalmente los archivos se guardan en un disco duro, disquete o CD-ROM.

Cuando hay un gran numero de archivos, suelen estar organizados en directorios (también llamados “carpetas”). Cada archivo se identifica con un nombre único, o una combinación de nombre de archivo y nombre de directorio.

Leyendo y escribiendo archivos, los programas pueden intercambiar información entre ellos y generar formatos imprimibles como PDF.

Trabajar con archivos se parece mucho a trabajar con libros. Para usar un libro, tiene que abrirlo. Cuando ha terminado, tiene que cerrarlo. Mientras el libro esta abierto, puede escribir en el o leer de el. En cualquier caso, sabe en que lugar del libro se encuentra. Casi siempre lee el libro según su orden natural, pero también puede ir saltando de una pagina a otra.

Todo esto sirve también para los archivos. Para abrir un archivo, especifique su nombre e indique si quiere leer o escribir.

La apertura de un archivo crea un objeto archivo. En este ejemplo, la variable f apunta al nuevo objeto archivo.

   1: >>> f = open("test.dat","w")

   2: >>> print f

   3: <open file 'test.dat', mode 'w' at fe820>

La función open toma dos argumentos. El primero es el nombre del archivo y el segundo es el modo. El modo ‘w’ (write) significa que lo estamos abriendo para escribir.

Si no hay un archivo llamado test.dat se creara. Si ya hay uno, el archivo que estamos escribiendo lo reemplazara.

Al imprimir el objeto archivo, vemos el nombre del archivo, el modo y la localización del objeto.

Para meter datos en el archivo invocamos al metodo write sobre el objeto archivo:

   1: >>> f.write("Ya es hora")

   2: >>> f.write("de cerrar el archivo")

El cierre del archivo le dice al sistema que hemos terminado de escribir y deja el archivo listo para leer:

   1: >>> f.close()

Ya podemos abrir el archivo de nuevo, esta vez para lectura, y poner su contenido en una cadena. Esta vez el argumento de modo es ‘r’ (read) para lectura:

   1: >>> f = open("test.dat","r")

Si intentamos abrir un archivo que no existe, recibimos un mensaje de error:

   1: >>> f = open("test.cat","r")

   2: IOError: [Errno 2] No such file or directory: 'test.cat'

Como era de esperar, el metodo read lee datos del archivo. Sin argumentos, lee el archivo completo:

   1: >>> text = f.read()

   2: >>> print text

   3: Ya es horade cerrar el archivo

No hay un espacio entre “hora” y “de” porque no escribimos un espacio entre las cadenas.

read también puede aceptar un argumento que le indica cuantos caracteres leer:

   1: >>> f = open("test.dat","r")

   2: >>> print f.read(7)

   3: Ya es h

Si no quedan suficientes caracteres en el archivo, read devuelve los que haya.

Cuando llegamos al final del archivo, read devuelve una cadena vacía:

   1: >>> print f.read(1000006)

   2: orade cerrar el archivo

   3: >>> print f.read()

   4: >>>

La siguiente función copia un archivo, leyendo y escribiendo los caracteres de cincuenta en cincuenta. El primer argumento es el nombre del archivo original; el segundo es el nombre del archivo nuevo:

   1: def copiaArchivo(archViejo, archNuevo):

   2:     f1 = open(archViejo, "r")

   3:     f2 = open(archNuevo, "w")

   4:     while 1:

   5:         texto = f1.read(50)

   6:         if texto == "":

   7:             break

   8:         f2.write(texto)

   9:     f1.close()

  10:     f2.close()

  11:     return

La sentencia break es nueva. Su ejecución interrumpe el bucle; el flujo de la ejecución pasa a la primera sentencia tras el bucle.

En este ejemplo, el bucle while es infinito porque el valor 1 siempre es verdadero.

La única forma de salir del bucle es ejecutar break, lo que sucede cuando texto es una cadena vacía, lo que sucede cuando llegamos al final del archivo.

11.1. Archivos de texto

Un archivo de texto es un archivo que contiene caracteres imprimibles y espacios organizados en líneas separadas por caracteres de salto de línea. Como Python esta diseñado específicamente para procesar archivos de texto, proporciona métodos que facilitan la tarea.

Para hacer una demostración, crearemos un archivo de texto con tres líneas de texto separadas por saltos de línea:

   1: >>> f = open("test.dat","w")

   2: >>> f.write("línea unonl³nea dosnlínea tresn")

   3: >>> f.close()

El metodo readline lee todos los caracteres hasta e inclusive el siguiente salto de línea:

   1: >>> f = open("test.dat","r")

   2: >>> print f.readline()

   3: línea uno

   4: >>>

readlines devuelve todas las líneas que queden como una lista de cadenas:

   1: >>> print f.readlines()

   2: ['línea dos12', 'línea tres12']

En este caso, la salida esta en forma de lista, lo que significa que las cadenas aparecen con comillas y el carácter de salto de línea aparece como la secuencia de escape 012.

Al final del archivo, readline devuelve una cadena vacía y readlines devuelve una lista vacía:

   1: >>> print f.readline()

   2: >>> print f.readlines()

   3: []

Lo que sigue es un ejemplo de un programa de proceso de líneas. filtraArchivo hace una copia de archViejo, omitiendo las líneas que comienzan por #:

   1: def filtraArchivo(archViejo, archNuevo):

   2:     f1 = open(archViejo, "r")

   3:     f2 = open(archNuevo, "w")

   4:     while 1:

   5:         texto = f1.readline()

   6:         if texto == "":

   7:             break

   8:         if texto[0] == '#':

   9:             continue

  10:         f2.write(texto)

  11:     f1.close()

  12:     f2.close()

  13:     return

La sentencia continue termina la iteración actual del bucle, pero sigue haciendo bucles. El flujo de ejecución pasa al principio del bucle, comprueba la condición y continua en consecuencia.

Así, si texto es una cadena vacía, el bucle termina. Si el primer carácter de texto es una almohadilla, el flujo de ejecución va al principio del bucle. Solo si ambas condiciones fallan copiamos texto en el archivo nuevo.

11.2. Escribir variables

El argumento de write debe ser una cadena, así que si queremos poner otros valores en un archivo, tenemos que convertirlos antes en cadenas. La forma mas fácil de hacerlo es con la función str:

   1: >>> x = 52

   2: >>> f.write (str(x))

Una alternativa es usar el operador de formato %. Cuando aplica a enteros, % es el operador de modulo. Pero cuando el primer operando es una cadena, % es el operador de formato.

El primer operando es la cadena de formato, y el segundo operando es una tupla de expresiones. El resultado es una cadena que contiene los valores de las expresiones, formateados de acuerdo a la cadena de formato.

A modo de ejemplo simple, la secuencia de formato ‘%d’ significa que la primera expresión de la tupla debería formatearse como un entero. Aquí la letra d quiere decir “decimal”:

   1: >>> motos = 52

   2: >>> "%d" % motos

   3: '52'

El resultado es la cadena ’52’, que no debe confundirse con el valor entero 52.

Una secuencia de formato puede aparecer en cualquier lugar de la cadena de formato, de modo que podemos incrustar un valor en una frase:

   1: >>> motos = 52

   2: >>> "En julio vendimos %d motos." % motos

   3: 'En julio vendimos 52 motos.'

La secuencia de formato ‘%f’ formatea el siguiente elemento de la tupla como un numero en coma flotante, y ‘%s’ formatea el siguiente elemento como una cadena:

   1: >>> "En %d días ingresamos %f millones de %s."

   2: % (34,6.1,'dolares')

   3: 'En 34 días ingresamose 6.100000 miliones de dolares.'

Por defecto, el formato de coma flotante imprime seis decimales.

El numero de expresiones en la tupla tiene que coincidir con el numero de secuencias de formato de la cadena. Igualmente, los tipos de las expresiones deben coincidir con las secuencias de formato:

   1: >>> "%d %d %d" % (1,2)

   2: TypeError: not enough arguments for format string

   3: >>> "%d" % 'dolares'

   4: TypeError: illegal argument type for built-in operation

En el primer ejemplo, no hay suficientes expresiones; en el segundo, la expresiones de un tipo incorrecto.

Para tener mas control sobre el formato de los números, podemos detallar el numero de dígitos como parte de la secuencia de formato:

   1: >>> "%6d" % 62

   2: ' 62'

   3: >>> "%12f" % 6.1

   4: ' 6.100000'

El numero tras el signo de porcentaje es el numero mínimo de espacios que ocupara el numero. Si el valor necesita menos dígitos, se añaden espacios en blanco delante del numero. Si el numero de espacios es negativo, se añaden los espacios tras el numero:

   1: >>> "%-6d" % 62

   2: '62

También podemos especificar el numero de decimales para los números en coma flotante:

   1: >>> "%12.2f" % 6.1

   2: ' 6.10'

En este ejemplo, el resultado ocupa doce espacios e incluye dos dígitos tras la coma. Este formato es útil para imprimir cantidades de dinero con las comas alineadas.

Imagine, por ejemplo, un diccionario que contiene los nombres de los estudiantes como clave y las tarifas horarias como valores. He aquí una función que imprime el contenido del diccionario como un informe formateado:

   1: def informe (tarifas) :

   2:     estudiantes = tarifas.keys()

   3:     estudiantes.sort()

   4:         for estudiante in estudiantes :

   5:             print "%-20s %12.02f" % (estudiante, tarifas[estudiante])

Para probar la función, crearemos un pequeño diccionario e imprimiremos el contenido:

 

   1: >>> tarifas = {'maría': 6.23, 'josé': 5.45, 'jesús': 4.25}

   2: >>> informe (tarifas)

   3: josé              5.45

   4: jesús             4.25

   5: maría             6.23

Controlando la anchura de cada valor nos aseguramos de que las columnas van a quedar alineadas, siempre que los nombres tengan menos de veintiún caracteres y las tarifas sean menos de mil millones la hora.

 

11.3. Directorios

Cuando usted crea un archivo nuevo abriéndolo y escribiendo, el nuevo archivo va al directorio en uso (aquel en el que estuviese al ejecutar el programa).

Del mismo modo, cuando abre un archivo para leerlo, Python lo busca en el directorio en uso.

Si quiere abrir un archivo de cualquier otro sitio, tiene que especificar la ruta del archivo, que es el nombre del directorio (o carpeta) donde se encuentra este:

   1: >>> f = open("/usr/share/dict/words","r")

   2: >>> print f.readline()

   3: Aarhus

Este ejemplo abre un archivo llamado words que esta en un directorio llamado dict, que esta en share, que esta en usr, que esta en el directorio de nivel superior del sistema, llamado.

No puede usar / como parte del nombre de un archivo; esta reservado como delimitador entre nombres de archivo y directorios.

El archivo /usr/share/dict/words contiene una lista de palabras en orden alfabético, la primera de las cuales es el nombre de una universidad danesa.

11.4. Encurtido

Para poner valores en un archivo, debe convertirlos en cadenas. Ya ha visto como hacerlo con str:

   1: >>> f.write (str(12.3))

   2: >>> f.write (str([1,2,3]))

El problema es que cuando vuelve usted a leer el valor, obtiene una cadena. Ha perdido la información del tipo de dato original. En realidad, no puede distinguir donde termina un valor y comienza el siguiente:

   1: >>> f.readline()

   2: '12.3[1, 2, 3]'

La solución es el encurtido, llamado así porque “conserva” estructuras de datos.

El modulo pickle contiene las ordenes necesarias. Para usarlo, importe pickle y luego abra el archivo de la forma habitual:

   1: >>> import pickle

   2: >>> f = open("test.pck","w")

Para almacenar una estructura de datos, use el metodo dump y luego cierre el archivo de la forma habitual:

   1: >>> pickle.dump(12.3, f)

   2: >>> pickle.dump([1,2,3], f)

   3: >>> f.close()

Ahora podemos abrir el archivo para leer y cargar las estructuras de datos que volcamos ahí:

   1: >>> f = open("test.pck","r")

   2: >>> x = pickle.load(f)

   3: >>> x

   4: 12.3

   5: >>> type(x)

   6: <type 'float'>

   7: >>> y = pickle.load(f)

   8: >>> y

   9: [1, 2, 3]

  10: >>> type(y)

  11: <type 'list'>

Cada vez que invocamos load obtenemos un valor del archivo, completo con su tipo original.

11.5. Excepciones

Siempre que ocurre un error en tiempo de ejecución, se crea una excepción.

Normalmente el programa se para y Python presenta un mensaje de error.

Por ejemplo, la división por cero crea una excepción:

   1: >>> print 55/0

   2: ZeroDivisionError: integer division or modulo

Un elemento no existente en una lista hace lo mismo:

   1: >>> a = []

   2: >>> print a[5]

   3: IndexError: list index out of range

O el acceso a una clave que no está en el diccionario:

 

   1: >>> b = {}

   2: >>> print b['qué']

   3: KeyError: qué

En cada caso, el mensaje de error tiene dos partes: el tipo de error antes de los dos puntos y detalles sobre el error después de los dos puntos. Normalmente Python también imprime una traza de donde se encontraba el programa, pero
la hemos omitido en los ejemplos.

A veces queremos realizar una operación que podría provocar una excepción, pero no queremos que se pare el programa. Podemos manejar la excepción
usando las sentencias try y except.

Por ejemplo, podemos preguntar al usuario por el nombre de un archivo y luego intentar abrirlo. Si el archivo no existe, no queremos que el programa se pare;  queremos manejar la excepción.

   1: nombreArch = raw_input('Introduce un nombre de archivo: ')

   2: try:

   3:     f = open (nombreArch, "r")

   4: except:

   5:     print 'No hay ning¶un archivo que se llame', nombreArch

La sentencia try ejecuta las sentencias del primer bloque. Si no se produce ninguna excepción, pasa por alto la sentencia excepto. Si ocurre cualquier excepción, ejecuta las sentencias de la rama except y después continua.

Podemos encapsular esta capacidad en una función: existe acepta un nombre de archivo y devuelve verdadero si el archivo existe y falso si no:

 

   1: def existe(nombreArch):

   2: try:

   3: f = open(nombreArch)

   4: f.close()

   5:     return 1

   6: except:

   7:     return 0

Puede usar múltiples bloques except para manejar diferentes tipos de excepciones. El Manual de Referencia de Python contiene los detalles.

Si su programa detecta una condición de error, puede hacer que lance (raise en ingles) una excepción. Aquí tiene usted un ejemplo que acepta una entrada del usuario y comprueba si es 17. Suponiendo que 17 no es una entrada valida por cualquier razón, lanzamos una excepción.

   1: def tomaNumero () :                                 # Recuerde, los acentos estan

   2: x = input ('Elige un numero: ')                     # prohibidos en los nombres

   3: if x == 17 :                                        # de funciones y variables!

   4:     raise 'ErrorNumeroMalo', '17 es un mal numero'

   5: return x

La sentencia raise acepta dos argumentos: el tipo de excepción e información específica acerca del error. ErrorNumeroMalo es un nuevo tipo de excepción que hemos inventado para esta aplicación.

Si la función llamada tomaNumero maneja el error, el programa puede continuar; en caso contrario, Python imprime el mensaje de error y sale:

   1: >>> tomaNumero ()

   2: Elige un numero: 17

   3: ErrorNumeroMalo: 17 es un mal numero

El mensaje de error incluye el tipo de excepción y la información adicional que usted proporcionó.

Como ejercicio, escriba una función que use tomaNumero para leer
un numero del teclado y que maneje la excepción ErrorNumeroMalo.

11.6. Glosario

archivo: Una entidad con nombre, normalmente almacenada en un disco duro, disquete o CD-ROM, que contiene una secuencia de caracteres.

directorio: Una colección, con nombre, de archivos, también llamado carpeta.

ruta: Una secuencia de nombres de directorio que especifica la localización exacta de un archivo.archivo de texto: Un archivo que contiene caracteres imprimibles organizados en líneas separadas por caracteres de salto de l³nea.

sentencia break: Una sentencia que provoca que el flujo de ejecución salga de un bucle.

sentencia continue: Una sentencia que provoca que termine la iteración actual de un bucle. El flujo de la ejecución va al principio del bucle, evalúa la condición, y procede en consecuencia.

operador de formato: El operador % toma una cadena de formato y una tupla de expresiones y entrega una cadena que incluye las expresiones, formateadas de acuerdo con la cadena de formato.

cadena de formato: Una cadena que contiene caracteres imprimibles y secuencias de formato que indican como formatear valores.

secuencia de formato: Una secuencia de caracteres que comienza con % e indica como formatear un valor.

encurtir: Escribir el valor de un dato en un archivo junto con la información sobre su tipo de forma que pueda ser reconstituido mas tarde.

excepción: Un error que ocurre en tiempo de ejecución.

manejar: Impedir que una excepción detenga un programa utilizando las sentencias try y except.

lanzar: Señalar una excepción usando la sentencia raise.

Página 11 de 22

Creado con WordPress & Tema de Anders Norén