Biblioteca Online : ¡La Suscripción ENI por 9,90 € el primer mes!, con el código PRIMER9. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Python 3
  3. Manipulación de datos
Extrait - Python 3 Los fundamentos del lenguaje (4ª edición)
Extractos del libro
Python 3 Los fundamentos del lenguaje (4ª edición) Volver a la página de compra del libro

Manipulación de datos

Manipular los archivos

1. Abrir un archivo

Python se diseñó originalmente para realizar operaciones de sistema, naturalmente se proporciona con herramientas muy extensas, muy fáciles de usar y muy efectivas. En una palabra, pythónicas. Y se han mejorado a lo largo de la evolución del lenguaje. Aquí está la forma básica de abrir un archivo:

>>> with open('test.txt') as f:  
...     pass # Trabajar en el contenido del archivo  
... 

¿Qué representa la f?

>>> with open('test.txt') as f:  
...     type(f)  
...     type.mro(type(f))  
...     dir(f)  
...   
<class '_io.TextIOWrapper'>  
[<class '_io.TextIOWrapper'>, <class '_io._TextIOBase'>, <class '_io._IOBase'>, 
<class 'object'>]  
['_CHUNK_SIZE', '__class__', '__delattr__', '__doc__', '__enter__', '__eq__', 
'__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', 
'__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__ne__', 
'__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', 
'__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', 
'_checkSeekable', '_checkWritable', 'buffer', 'close', 'closed', 'detach', 
'encoding', 'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'name', 
'newlines', 'read', 'readable', 'readline', 'readlines', 'seek', 'seekable', 
'tell', 'truncate', 'writable', 'write', 'writelines'] 

La variable f es una estructura que corresponde a una entrada/salida (descriptor de archivo) y que puede usarse como generador.

Veremos como usar esta variable para satisfacer diferentes necesidades.

Antes de eso, es útil...

Herramienta de copia de seguridad

Un programa puede tener una o más formas de finalizar. También puede terminar con una excepción. Por estas razones, se debe proporcionar alguna forma de realizar acciones, independientemente de cómo termine el programa (esto no funciona cuando Python termina por señales externas ignoradas o errores fatales).

>>> datas = {}  
>>> @atexit.register  
... def quit():  
...     print('Copia de seguridad de los datos')  
... 

Ejecutar [Ctrl] + d en la consola, para salir y probar la funcionalidad.

Leer un archivo de configuración

Los archivos de configuración pueden ser de diferentes estructuras. Algunos están en XML y, en este caso, debe usar un analizador XML para recuperar información útil (como archivos zcml de zope) o archivos de configuración de muchas aplicaciones Java, como Sonar, por ejemplo.

Los otros son los archivos clásicos de CONF para Unix o INI para Windows, pero también Unix (php.ini, por ejemplo).

Hay un módulo específico que le permite leer archivos INI como los que se encuentran en Windows. Aquí hay uno:

$ cat /tmp/test.ini  
[SQL]  
backoffice_url = postgres://user:pass@host/base  
frontoffice_url = postgres://user:pass@host/base  
  
[EXPORT]  
directory = '/var/saves/csv/'  
filename = 'export_%s.txt'  
  
[SERVER]  
port = 8016  
webdav = yes  
sftp = yes 

Aquí se explica como parsear este archivo:

>>> import configparser  
>>> parser = configparser.ConfigParser()  
>>> parser.read('/tmp/test.ini')  
['/tmp/test.ini'] 

Entonces es fácil recuperar las diferentes secciones:

>>> parser.sections()  
['SQL', 'EXPORT', 'SERVER'] 

El analizador puede usarse como un diccionario y cada sección también:...

Formato de exportación/importación

1. CSV

CSV es la abreviatura de Comma Separated Values y es, en su origen, un archivo de texto que contiene datos separados por comas. No obstante, el hecho de que la coma pueda utilizarse en un valor, y otras problemáticas relativas al contenido de los datos y a los hábitos de representación inherentes a los distintos lenguajes, han hecho aparecer otros formatos, que se llaman dialectos. Estas son las principales diferencias, dejando a un lado los dialectos:

  • Los datos se presentan en forma de tabla.

  • Cada fila del archivo CSV se corresponde con una fila de la tabla.

  • Cada columna del archivo CSV está delimitada a la derecha y a la izquierda por el separador o (exclusivo) por un final de línea.

  • La primera fila del archivo puede utilizarse para contener los encabezados de las columnas, aunque esto no es obligatorio.

  • En función del formalismo, puede admitirse que no todas las filas tengan el mismo número de columnas, o bien esto puede considerarse como un error.

De cara a trabajar con datos reales, con cierto sentido y susceptibles de ser manipulados, se incluyen en los archivos para descargar varios documentos que contienen datos relativos a los municipios, provincias y comunidades autónomas de España.

Python dispone de las herramientas necesarias para acceder, a bajo nivel, a los datos de un archivo CSV, pero también dispone de las herramientas necesarias para representar estos datos mediante simples listas y diccionarios, que son objetos habituales en Python, y fáciles de manipular. El módulo se denomina csv y forma parte de las librerías integradas de Python, de modo que está incluida en Python 3.

>>> import csv 

He aquí la primera dificultad. Trabajar con CSV se realiza, exclusivamente, en Unicode, que es el formato de las cadenas de caracteres por defecto de la rama 3 de Python. Puede que los archivos que queramos leer no sean archivos Unicode.

Su lectura produce un error:

>>> with open('comaut.txt', 'r') as f:  
...     datas = csv.reader(f)  
...     next(datas)  
...   
Traceback (most recent call last):  
   File "<stdin>", line 3, in <module>  
   File "/usr/lib/python3.2/codecs.py", line 300, in decode  
   ...

Comprimir y descomprimir un archivo

1. Tarfile

Comprimir un archivo es una forma de reducir su tamaño sin pérdida de información. Para esto, hay diferentes algoritmos que se pueden usar en Python.

Antes de abordarlos, debe saber que es posible comprimir varios archivos mediante estos mismos algoritmos, simplemente uniendo los archivos uno detrás del otro de forma reversible, para posteriormente pasar el algoritmo de compresión al archivo único obtenido. Los archivos unitarios se nombran miembros del archivo global. Para obtener un archivo que contenga archivos ya comprimidos (archivos PNG u ODT, por ejemplo, un tar es suficiente).

El algoritmo para realizar esta operación es tar y la biblioteca de archivos tar de Python le permite trabajar con dichos archivos.

Deje que los siguientes dos archivos sean:

$ cat /tmp/archivo1.txt  
Primera línea  
Segunda línea  
$ cat /tmp/archivo2.txt  
Primera línea  
Segunda línea  
Tercera línea 

Aquí se explica como construir un archivo tar:

>>> import tarfile  
>>> with tarfile.open('/tmp/test.tar', 'w') as f:  
...     f.add('/tmp/archivo1.txt')  
...     f.add('/tmp/archivo2.txt')  
... 

El resultado es:

$ cat /tmp/test.tar  
tmp/archivo1.txt0000644000175000017500000000003611641322375013470  
0ustar  schsch00000000000000Primera línea  
Segunda línea  
tmp/archivo2.txt0000644000175000017500000000006111641322424013462  
0ustar  schsch00000000000000Primera línea  
Segunda línea  
Tercera línea 

Esta operación está muy cerca de un trabajo en un archivo clásico.

También es posible leer un archivo usando el segundo parámetro r en lugar de w o no poniendo:

>>> with tarfile.open('/tmp/test.tar') as f:  
...     f.extractall('/tmp/test')  
... 

Aquí también la operación es sencilla.

Veamos ahora el resultado:

$ ll /tmp/test/  
total 4  
drwxr-xr-x  3 sch  sch    16 2011-09-30 13:37 ./  
drwxrwxrwt 17 root root 4096 2011-09-30 13:37 ../  
drwxr-xr-x  2 sch  sch    44 2011-09-30...

Herramientas de manipulación de datos

1. Generar números aleatorios

Una serie de números aleatorios es una serie de números en la que el siguiente número de la lista no puede predecirse de manera determinista (basándose en otros números de la lista, o en consideraciones del material...).

Si bien encontrar tres o cuatro números aleatorios es una tarea trivial, poder proveer una gran cantidad de ellos se convierte en una problemática de las más complejas de resolver y que capta la atención de los matemáticos.

El lenguaje Python proporciona un módulo dedicado a la generación de números aleatorios y que está orientado al usuario, pues proporciona funcionalidades realmente adaptadas a las necesidades del usuario. He aquí el módulo que debemos importar:

>>> import random 

La funcionalidad clásica consiste en seleccionar un número comprendido entre dos valores: 

>>> random.randint(512, 1024) 
909 

En Python, esto se realiza de manera muy sencilla y los límites están incluidos dentro de las opciones posibles. Habitualmente, esta base se utiliza para todos los demás tipos de necesidades. Por ejemplo, para seleccionar un elemento en una lista, contamos el número de elementos y seleccionamos un número que se corresponda con el índice del elemento seleccionado en la lista. Esto es algo molesto.

En Python, podemos trabajar de manera elegante, rápida y definida:

>>> colores = ['azul', 'amarillo', 'rojo', 'verde', 'violeta', 
'naranja', 'marrón', 'blanco', 'negro'] 
>>> random.choice(colores) 
'amarillo' 

Basta con escribir una línea. Más difícil: deseamos seleccionar un cierto número de elementos de la lista, una muestra o algo similar:

>>> random.sample(colores, 3) 
['verde', 'naranja', 'rojo'] 

En este caso basta, también, con una línea. Por último, la mezcla de manera aleatoria de una lista se realiza directamente sobre la lista (modificación del propio objeto) y es relativamente óptimo:

>>> random.shuffle(colores) 
>>> colores 
['naranja', 'negro', 'azul'...

Criptografía ligera

1. Número aleatorio seguro

Para fines puramente criptográficos, es útil poder generar secuencias de bytes aleatoriamente y el módulo aleatorio no ofrece suficientes garantías de su aleatoriedad. Esto es suficiente para las necesidades del programa convencional, pero no para la criptografía.

De hecho, ningún sistema informático puede generar números absolutamente aleatorios. Siempre llega un umbral a partir del cual la generación se vuelve predecible. Sin embargo, existen estándares para generarlos que son lo suficientemente seguros:

import ssl  
ssl.RAND_bytes(128) 

Por lo tanto, por este método es necesario generar un número aleatorio en un contexto relacionado con la criptografía.

También hay un módulo de Python dedicado a estos problemas de criptografía y que contiene un módulo aleatorio reforzado. Se establecerse como:

$ pip install pycrypto 

Y también se usa así:

>>> from Crypto.Random import random  
>>> random.choice([1, 2, 3])  
2 

Este módulo contiene todas las funciones habituales, pero la gestión de la aleatoriedad es más segura. Sin embargo, notará que no se respetan las reglas de nomenclatura, ya que el módulo debe estar en minúsculas.

2. Funciones de cifrado

El módulo hashlib permite ofrecer las funciones de hash habituales, que suelen respetar la misma interfaz.

Una función de hash permite obtener una firma a partir de una secuencia de bytes, que puede ser una cadena de caracteres en una codificación particular o bien un archivo. En este caso, hablamos de una firma digital.

Esta firma puede ser de dos tipos: una secuencia de bytes o un número hexadecimal.

>>> import hashlib  
>>> hashlib.algorithms_available  
{'SHA1', 'SHA224', 'SHA', 'SHA384', 'ecdsa-with-SHA1', 'SHA256', 
'SHA512', 'md4', 'md5', 'sha1', 'dsaWithSHA', 'DSA-SHA', 'sha224', 
'dsaEncryption', 'DSA', 'ripemd160', 'sha', 'MD5', 'MD4',  
'sha384', 'sha256', 'sha512', 'RIPEMD160'}  
>>> hashlib.algorithms_guaranteed  ...