Lección 6 Archivos
Veremos las capacidades que python nos permiter tener a la hora de leer, guardar archivos
E/S de archivos
Hasta ahora, todo lo que hemos programado ha almacenado información en la memoria. Es decir, una vez finalizado el programa, toda la información recopilada del usuario o generada por el programa se pierde.
La E/S de archivos es la capacidad de un programa de tomar un archivo como entrada o crear un archivo como salida.
Para comenzar, en la ventana de terminal escriba
code names.py
otouch names.py
y codifique de la siguiente manera:name = input("What's your name?" ) print(f"hello, {name}")
Observe que ejecutar este código tiene el resultado deseado. El usuario puede ingresar un nombre. El resultado es el esperado.
Sin embargo, ¿qué pasaría si quisiéramos permitir la entrada de varios nombres? ¿Cómo podríamos lograr esto? Recuerde que a
list
es una estructura de datos que nos permite almacenar múltiples valores en una sola variable. Codifique de la siguiente manera:names = [] for _ in range(3): name = input("What's your name?" ) names.append(name)
Observe que se le pedirá al usuario que ingrese tres veces. El
append
método se utiliza para agregarname
a nuestranames
lista.Este código podría simplificarse a lo siguiente:
names = [] for _ in range(3): names.append(input("What's your name?" ))
Observe que esto tiene el mismo resultado que el bloque de código anterior.
- Ahora, habilitemos la capacidad de imprimir la lista de nombres como una lista ordenada. Codifique de la siguiente manera:
names = [] for _ in range(3): names.append(input("What's your name?" )) for name in sorted(names): print(f"hello, {name}")
Observe que una vez que se ejecuta este programa, toda la información se pierde. File I/O permite que su programa almacene esta información para poder utilizarla más adelante.
Puede obtener más información en la documentación de Python de sorted .
open
open
es una funcionalidad integrada en Python que le permite abrir un archivo y utilizarlo en su programa. Laopen
función le permite abrir un archivo para que pueda leerlo o escribirlo.Para mostrarle cómo habilitar la E/S de archivos en su programa, retrocedamos un poco y codifiquemos de la siguiente manera:
name = input("What's your name? ") file = open("names.txt", "w") file.write(name) file.close()
Observe que la
open
función abre un archivo llamadonames.txt
con la escritura habilitada, como lo indica el archivow
. El código anterior asigna ese archivo abierto a una variable llamadafile
. La líneafile.write(name)
escribe el nombre en el archivo de texto. La línea siguiente cierra el archivo.Al probar su código escribiendo
python names.py
, puede ingresar un nombre y se guarda en el archivo de texto. Sin embargo, si ejecuta su programa varias veces con nombres diferentes, notará que este programa reescribirá completamente elnames.txt
archivo cada vez.Idealmente, queremos poder agregar cada uno de nuestros nombres al archivo. Elimine el archivo de texto existente escribiendo
rm names.txt
en la ventana del terminal. Luego, modifique su código de la siguiente manera:name = input("What's your name? ") file = open("names.txt", "a") file.write(name) file.close()
Tenga en cuenta que el único cambio en nuestro código es que se
w
ha cambiado aa
"añadir". Al volver a ejecutar este programa varias veces, notará que se agregarán nombres al archivo. Sin embargo, ¡notarás un nuevo problema!Al examinar su archivo de texto después de ejecutar su programa varias veces, notará que los nombres se ejecutan juntos. Los nombres se agregan sin espacios entre cada uno de los nombres. Puedes solucionar este problema. Nuevamente, elimine el archivo de texto existente escribiéndolo
rm names.txt
en la ventana del terminal. Luego, modifique su código de la siguiente manera:name = input("What's your name? ") file = open("names.txt", "a") file.write(f"{name}\n") file.close()
Observe que la línea con
file.write
se ha modificado para agregar un salto de línea al final de cada nombre.Este código está funcionando bastante bien. Sin embargo, hay formas de mejorar este programa. Sucede que es bastante fácil olvidarse de cerrar el archivo.
Puede obtener más información en la documentación de Python de open .
with
La palabra clave
with
le permite automatizar el cierre de un archivo.Modifique su código de la siguiente manera:
name = input("What's your name? ") with open("names.txt", "a") as file: file.write(f"{name}\n")
Observe que la línea siguiente
with
tiene sangría.Hasta este momento, hemos estado escribiendo exclusivamente en un archivo. ¿Qué pasa si queremos leer de un archivo? Para habilitar esta funcionalidad, modifique su código de la siguiente manera:
with open("names.txt", "r") as file: lines = file.readlines() for line in lines: print("hello,", line)
Fíjate que
readlines
tiene una habilidad especial para leer todas las líneas de un archivo y almacenarlas en un archivo llamado líneas. Al ejecutar su programa, notará que el resultado es bastante feo. Parece haber varios saltos de línea donde debería haber solo uno.Existen muchos enfoques para solucionar este problema. Sin embargo, aquí hay una forma sencilla de corregir este error en nuestro código:
with open("names.txt", "r") as file: lines = file.readlines() for line in lines: print("hello,", line.rstrip())
Observe que
rstrip
tiene el efecto de eliminar el salto de línea extraño al final de cada línea.Aún así, este código podría simplificarse aún más:
with open("names.txt", "r") as file: for line in file: print("hello,", line.rstrip())
Observe que al ejecutar este código, es correcto. Sin embargo, observe que no estamos ordenando los nombres.
Este código podría mejorarse aún más para permitir la clasificación de los nombres:
names = [] with open("names.txt") as file: for line in file: names.append(line.rstrip()) for name in sorted(names): print(f"hello, {name}")
Observe que
names
hay una lista en blanco donde podemos recopilar los nombres. Cada nombre se agrega a lanames
lista en la memoria. Luego, se imprime cada nombre en la lista ordenada en la memoria. Al ejecutar su código, verá que los nombres ahora están ordenados correctamente.¿Qué pasaría si quisiéramos tener la capacidad de almacenar algo más que los nombres de los estudiantes? ¿Qué pasaría si quisiéramos almacenar tanto el nombre del estudiante como su casa también?
CSV
CSV significa "valores separados por comas".
En la ventana de su terminal, escriba
code students.csv
. Asegúrese de que su nuevo archivo CSV tenga el siguiente aspecto:Hermoine,Gryffindor Harry,Gryffindor Ron,Gryffindor Draco,Slytherin
Creemos un nuevo programa escribiendo
code students.py
y codificando de la siguiente manera:with open("students.csv") as file: for line in file: row = line.rstrip().split(",") print(f"{row[0]} is in {row[1]}")
Observe que
rstrip
elimina el final de cada línea en nuestro archivo CSV.split
le dice al compilador dónde encontrar el final de cada uno de nuestros valores en nuestro archivo CSV.row[0]
es el primer elemento en cada línea de nuestro archivo CSV.row[1]
es el segundo elemento en cada línea de nuestro archivo CSV.El código anterior es eficaz para dividir cada línea o "registro" de nuestro archivo CSV. Sin embargo, resulta un poco críptico si no estás familiarizado con este tipo de sintaxis. Python tiene una capacidad incorporada que podría simplificar aún más este código. Modifique su código de la siguiente manera:
with open("students.csv") as file: for line in file: name, house = line.rstrip().split(",") print(f"{name} is in {house}")
Observe que la
split
función en realidad devuelve dos valores: el que está antes de la coma y el que está después de la coma. En consecuencia, podemos confiar en esa funcionalidad para asignar dos variables a la vez en lugar de una.¿Imagínese que quisiéramos volver a proporcionar esta lista como resultado ordenado? Puede modificar su código de la siguiente manera:
students = [] with open("students.csv") as file: for line in file: name, house = line.rstrip().split(",") students.append(f"{name} is in {house}") for student in sorted(students): print(student)
Observe que creamos un
list
llamadostudents
. Cada uno de nosotrosappend
pertenece a esta lista. Luego, generamos una versión ordenada de nuestra lista.Recuerde que Python permite
dictionaries
asociar una clave con un valor. Este código podría mejorarse aún más.students = [] with open("students.csv") as file: for line in file: name, house = line.rstrip().split(",") student = {} student["name"] = name student["house"] = house students.append(student) for student in students: print(f"{student['name']} is in {student['house']}")
Observe que creamos un diccionario vacío llamado
student
. Agregamos los valores de cada estudiante, incluido su nombre y casa, alstudent
diccionario. Luego, agregamos ese estudiante allist
llamadostudents
.Podemos mejorar nuestro código para ilustrar esto de la siguiente manera:
students = [] with open("students.csv") as file: for line in file: name, house = line.rstrip().split(",") student = {"name": name, "house": house} students.append(student) for student in students: print(f"{student['name']} is in {student['house']}")
Observe que esto produce el resultado deseado, menos la clasificación de los estudiantes.
Desafortunadamente, no podemos ordenar a los estudiantes como lo hacíamos antes porque ahora cada estudiante es un diccionario dentro de una lista. Sería útil si Python pudiera ordenar la
students
lista destudent
diccionarios por el nombre del estudiante.Para implementar esto en nuestro código, realice los siguientes cambios:
students = [] with open("students.csv") as file: for line in file: name, house = line.rstrip().split(",") students.append({"name": name, "house": house}) def get_name(student): return student["name"] for student in sorted(students, key=get_name): print(f"{student['name']} is in {student['house']}")
Tenga en cuenta que
sorted
es necesario saber cómo obtener la clave de cada alumno. Python permite un parámetro llamadokey
donde podemos definir en qué "clave" se ordenará la lista de estudiantes. Por lo tanto, laget_name
función simplemente devuelve la clave destudent["name"]
. Al ejecutar este programa, verá que la lista ahora está ordenada por nombre.Aún así, nuestro código se puede mejorar aún más. Da la casualidad de que si solo va a utilizar una función
get_name
una vez, puede simplificar su código de la manera que se presenta a continuación. Modifique su código de la siguiente manera:students = [] with open("students.csv") as file: for line in file: name, house = line.rstrip().split(",") students.append({"name": name, "house": house}) for student in sorted(students, key=lambda student: student["name"]): print(f"{student['name']} is in {student['house']}")
Observe cómo usamos una
lambda
función, una función anónima, que dice “Oye Python, aquí hay una función que no tiene nombre: dado unstudent
, accede a suname
y devuélvelo alkey
.Desafortunadamente, nuestro código es un poco frágil. Supongamos que cambiamos nuestro archivo CSV de modo que indiquemos dónde creció cada estudiante. ¿Cuál sería el impacto de esto en nuestro programa? Primero, modifique su
students.csv
archivo de la siguiente manera:
Harry,"Number Four, Privet Drive"
Ron,The Burrow
Draco,Malfoy Manor
Observe cómo ejecutar nuestro programa producirá una serie de errores.
Ahora que estamos tratando con casas en lugar de casas, modifique su código de la siguiente manera:
students = [] with open("students.csv") as file: for line in file: name, home = line.rstrip().split(",") students.append({"name": name, "home": home}) for student in sorted(students, key=lambda student: student["name"]): print(f"{student['name']} is in {student['home']}")
Observe que ejecutar nuestro programa todavía no funciona correctamente. ¿Puedes adivinar por qué?
El
ValueError: too many values to unpack
error producido por el compilador es el resultado del hecho de que previamente creamos este programa esperando que el archivo CSV usarasplit
una,
(coma). Podríamos dedicar más tiempo a abordar esto, pero, de hecho, ¡alguien más ya ha desarrollado una forma de "analizar" (es decir, leer) archivos CSV!La biblioteca integrada de Python
csv
viene con un objeto llamadoreader
. Como sugiere el nombre, podemos usar areader
para leer nuestro archivo CSV a pesar de la coma adicional en "Número cuatro, Privet Drive". Areader
funciona en unfor
bucle, donde cada iteraciónreader
nos da otra fila de nuestro archivo CSV. Esta fila en sí es una lista, donde cada valor de la lista corresponde a un elemento de esa fila.row[0]
, por ejemplo, es el primer elemento de la fila dada, mientras querow[1]
es el segundo elemento.import csv students = [] with open("students.csv") as file: reader = csv.reader(file) for row in reader: students.append({"name": row[0], "home": row[1]}) for student in sorted(students, key=lambda student: student["name"]): print(f"{student['name']} is from {student['home']}")
Observe que nuestro programa ahora funciona como se esperaba.
Hasta este punto, hemos confiado en nuestro programa para decidir específicamente qué partes de nuestro archivo CSV son los nombres y qué partes son las casas. Sin embargo, es mejor diseñarlo directamente en nuestro archivo CSV editándolo de la siguiente manera:
name,home Harry,"Number Four, Privet Drive" Ron,The Burrow Draco,Malfoy Manor
Observe cómo decimos explícitamente en nuestro archivo CSV que cualquier cosa que lo lea debe esperar que haya un valor de nombre y un valor de inicio en cada línea.
Podemos modificar nuestro código para usar una parte de la
csv
biblioteca llamada aDictReader
para tratar nuestro archivo CSV con aún más flexibilidad:import csv students = [] with open("students.csv") as file: reader = csv.DictReader(file) for row in reader: students.append({"name": row["name"], "home": row["home"]}) for student in sorted(students, key=lambda student: student["name"]): print(f"{student['name']} is in {student['home']}")
Observe que hemos reemplazado
reader
conDictReader
, que devuelve un diccionario a la vez. Además, observe que el compilador accederá directamente alrow
diccionario, obteniendo elname
yhome
de cada estudiante. Este es un ejemplo de codificación defensiva. Siempre que la persona que diseña el archivo CSV haya ingresado la información correcta del encabezado en la primera línea, podemos acceder a esa información usando nuestro programa.Hasta este punto, hemos estado leyendo archivos CSV. ¿Qué pasa si queremos escribir en un archivo CSV?
Para empezar, limpiemos un poco nuestros archivos. Primero, elimine el
students.csv
archivo escribiéndolorm students.csv
en la ventana de la terminal. Este comando solo funcionará si estás en la misma carpeta que tustudents.csv
archivo.Luego, en
students.py
, modifica tu código de la siguiente manera:import csv name = input("What's your name? ") home = input("Where's your home? ") with open("students.csv", "a") as file: writer = csv.DictWriter(file, fieldnames=["name", "home"]) writer.writerow({"name": name, "home": home})
Observe cómo estamos aprovechando la funcionalidad incorporada de
DictWriter
, que requiere dos parámetros:file
en el que se escribe y en elfieldnames
que se escribe. Además, observe cómo lawriterow
función toma un diccionario como parámetro. Literalmente, le estamos diciendo al compilador que escriba una fila con dos campos llamadosname
yhome
.Tenga en cuenta que hay muchos tipos de archivos que puede leer y escribir.
Puede obtener más información en la documentación de CSV de Python .
Archivos binarios y PIL
- Un tipo más de archivo que discutiremos hoy es un archivo binario. Un archivo binario es simplemente una colección de unos y ceros. Este tipo de archivo puede almacenar cualquier cosa, incluidos datos de música e imágenes.
- Existe una biblioteca popular de Python llamada
PIL
que funciona bien con archivos de imagen. - Los GIF animados son un tipo popular de archivo de imagen que contiene muchos archivos de imagen que se reproducen en secuencia una y otra vez, creando una animación o efecto de vídeo simplista.
- Imaginemos que tenemos una serie de disfraces, como se ilustra a continuación.
- Aquí está
costume1.gif
.
- Aquí hay otro que se llama
costume2.gif
. Observe cómo las posiciones de las piernas son ligeramente diferentes.
Antes de continuar, asegúrese de haber descargado los archivos del código fuente del sitio web del curso. No le será posible codificar lo siguiente sin tener las dos imágenes anteriores en su poder y almacenadas en su IDE.
En la ventana de terminal escriba
code costumes.py
otouch costumes.py
y codifique de la siguiente manera:import sys from PIL import Image images = [] for arg in sys.argv[1:]: image = Image.open(arg) images.append(image) images[0].save( "costumes.gif", save_all=True, append_images=[images[1]], duration=200, loop=0 )
Observe que importamos la
Image
funcionalidad desdePIL
. Observe que el primerfor
bucle simplemente recorre las imágenes proporcionadas como argumentos de la línea de comandos y almacena el tema en ellist
archivoimages
. Comienza1:
a cortarargv
en su segundo elemento. Las últimas líneas de código guardan la primera imagen y también le agregan una segunda imagen, creando un gif animado. Escribiendopython costumes.py costume1.gif costume2.gif
en la terminal. Ahora, escribacode costumes.gif
en la ventana de la terminal y podrá ver un GIF animado.Puede obtener más información en la documentación de PIL de Pillow .
Resumiendo
Ahora bien, no sólo hemos visto que podemos escribir y leer archivos textualmente, sino que también podemos leer y escribir archivos usando unos y ceros. No podemos esperar a ver qué logras con estas nuevas habilidades a continuación.
- E/S de archivos
open
with
- CSV
PIL