Saltar al contenido
Inicio 100 Días de Código en Python — Día 24: Archivos, Directorios y Rutas

100 Días de Código en Python — Día 24: Archivos, Directorios y Rutas

Nivel: Grado décimo Área: Tecnología e Informática Modalidad: Tutorial práctico Fuente: Curso "100 Days of Code: The Complete Python Pro Bootcamp" (Angela Yu, App Brewery). Contenido del Día 24 (nivel intermedio).

Este tutorial adapta pedagógicamente el Día 24. Las secciones 📝 Ejercicio original del curso provienen de los archivos del curso. Los retos 🟢🟡🟠🔴, el proyecto extra y el proyecto integrador son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.

Nota sobre las verificaciones: todos los ejemplos con archivos se ejecutaron con Python 3.14 en Windows: los modos "r", "w" y "a", readlines, strip, los errores de int("") y de archivos inexistentes, las rutas de Windows dentro de un string y la lectura de tildes con y sin encoding. Los resultados que aparecen aquí son los obtenidos. La parte del juego de la serpiente se revisó siguiendo la lógica del código.


Tabla de contenidos

  1. Antes de empezar
  2. El problema: el récord que se olvida
  3. Abrir, leer, escribir y cerrar archivos
  4. Reto: guardar el récord de la serpiente en un archivo
  5. Rutas absolutas y relativas
  6. 🚀 Proyecto del día: la Combinación de Correspondencia (Mail Merge)
  7. 🌟 Proyecto extra: la Bitácora del Huerto Escolar
  8. 🏆 Proyecto integrador del Día 24: Generador de Informes para Acudientes
  9. 🧩 Comprueba lo aprendido
  10. 🤖 Programar con apoyo de IA
  11. 🛠️ Correcciones técnicas al material original
  12. 📋 Matriz de trazabilidad
  13. 📦 Evidencias de aprendizaje del Día 24

0. Antes de empezar

(Fuentes: 181 - Day 24 Goals- what you will make by the end of the day.md, 188 - What's the correct solution- What's the best answer- What's the right way-.md)

Hasta hoy, todo lo que hacían nuestros programas desaparecía al cerrarlos. Hoy aprenderemos a guardar y leer información en archivos, y a movernos entre carpetas con rutas.

Haremos dos cosas:

  1. Agregar un récord (puntaje más alto) al juego de la serpiente, que se conserve entre partidas.
  2. Automatizar una tarea repetitiva: escribir muchas cartas iguales cambiando solo el nombre, como invitaciones a un cumpleaños o a una graduación.

Mensaje de cierre del curso: ¿cuál es la solución correcta? No hay una solución correcta: hay tu solución y el razonamiento que te llevó a ella. El curso cita a Donald Knuth, autor de The Art of Computer Programming, sobre los peligros de la optimización prematura: no intentes que tu código sea lo más rápido o lo más corto posible. Busca que sea legible. Si otra persona entiende tu código sin esfuerzo, lo lograste. Como le dijo un profesor a Angela sobre sus ensayos: "Escribe para que otros entiendan lo que quieres decir", no para sonar inteligente.

Prerequisito general: el juego de la serpiente de los Días 20 y 21, conversión de tipos con int() y str() (Día 2), f-strings (Día 2), bucles for (Día 5), listas (Día 4) y métodos de strings.


1. El problema: el récord que se olvida

(Fuente: 182 - Add a High Score to the Snake Game.md)

🎯 Objetivo de aprendizaje

  • Agregar un récord al juego de la serpiente y reiniciar la partida sin cerrar el programa.
  • Explicar por qué las variables no sobreviven al cierre del programa.

📝 Ejercicio original del curso: récord y reinicio

Cambios en Scoreboard:

  1. Nuevo atributo self.high_score = 0.
  2. El método game_over() se reemplaza por reset():
Python
def reset(self):
    if self.score > self.high_score:
        self.high_score = self.score
    self.score = 0
    self.update_scoreboard()

¡El orden importa! Si pusieras self.score = 0 antes del if, el puntaje nunca superaría al récord.

  1. self.clear() pasa a estar dentro de update_scoreboard(). Antes no se podía hacer así, porque el GAME OVER necesitaba conservar el puntaje en pantalla. Ahora que no hay GAME OVER, se simplifica y se evita llamar clear() en dos lugares.
  2. El marcador muestra: f"Score: {self.score} High Score: {self.high_score}".

Cambios en Snake: un método reset() que "reinicia" la serpiente:

Python
def reset(self):
    for seg in self.segments:
        seg.goto(1000, 1000)      # manda los segmentos viejos fuera de la pantalla
    self.segments.clear()         # vacía la lista
    self.create_snake()
    self.head = self.segments[0]

El curso descubre que self.segments.clear() no borra las tortugas de la pantalla: solo las quita de la lista. Por eso primero las envía a (1000, 1000), fuera de la ventana de 600 × 600.

Cambios en main.py: al chocar con la pared o la cola, ya no se hace game_is_on = False; se llama scoreboard.reset() y snake.reset().

Análisis de esta adaptación: los segmentos enviados a (1000, 1000) siguen existiendo en la memoria. Tras muchas partidas se acumulan tortugas invisibles. Una alternativa más limpia es seg.hideturtle(). Para un juego escolar la diferencia es pequeña, pero es un buen ejemplo de que "que no se vea" no es lo mismo que "que no exista".

📖 ¿Por qué se pierde el récord?

El curso lo demuestra con un ejemplo mínimo:

Python
a = 3
a = int(input("¿Qué valor quieres para a? "))   # el usuario escribe 12
print(a)                                        # 12

Si vuelves a ejecutar el programa, a vuelve a ser 3. Cada ejecución empieza desde cero: las variables viven en la memoria RAM y se borran al terminar. Con el récord pasa lo mismo.

¿Cómo lo harías sin computador? Lo anotarías en una libreta o en un documento de Word y lo leerías la próxima vez que juegues. Eso haremos con Python: escribir y leer un archivo.


2. Abrir, leer, escribir y cerrar archivos

(Fuente: 183 - How to Open, Read, and Write to Files using the -with- Keyword.md)

🎯 Objetivo de aprendizaje

  • Usar open() con los modos "r", "w" y "a".
  • Explicar por qué se usa with.

📖 Explicación conceptual

open() es una función incorporada (no hay que importarla). Recibe el nombre del archivo y el modo:

Modo Significado Si el archivo no existe Si el archivo existe
"r" (por defecto) Leer (read) FileNotFoundError Lo lee
"w" Escribir (write) Lo crea Borra todo su contenido y escribe desde cero
"a" Agregar (append) Lo crea Escribe al final, sin borrar

Versión 1 del curso (abrir y cerrar a mano):

Python
file = open("my_file.txt")
contents = file.read()      # devuelve TODO el contenido como un string
print(contents)
file.close()                # libera los recursos del computador

¿Por qué cerrar? Un archivo abierto consume recursos, como una pestaña del navegador. Con 20 o 30 pestañas, el computador se pone lento. Consejo del curso: cierra las pestañas y los archivos que ya no uses.

Versión 2 (la recomendada): with

Python
with open("my_file.txt") as file:
    contents = file.read()
    print(contents)
# al salir del bloque, Python cierra el archivo automáticamente

Escribir y agregar:

Python
with open("my_file.txt", mode="w") as file:
    file.write("Nuevo texto.")          # reemplaza todo el contenido

with open("my_file.txt", mode="a") as file:
    file.write("\nNuevo texto.")        # \n = salto de línea, agregado al final

(Verificado: escribir "Hola\n" con "w" y luego "Nuevo texto" con "a" deja el archivo con 'Hola\nNuevo texto'.)

🛠️ Nota técnica (verificada): las tildes y la ñ

El curso no especifica la codificación de los archivos. En español esto es importante. En Windows, si no se indica, Python usa la codificación del sistema (en la prueba, cp1252), mientras que los editores modernos como PyCharm y VS Code guardan en UTF-8. Resultado de la prueba: un archivo UTF-8 con "Querida Sofía, ñandú" leído sin encoding se ve como "Querida Sofía, ñandú".

Solución: indica siempre la codificación:

Python
with open("carta.txt", encoding="utf-8") as file:
    contents = file.read()

Adóptalo como buena práctica desde hoy: encoding="utf-8" en todo open() con textos en español.

⚠️ Errores frecuentes

Error Mensaje o síntoma Solución
Escribir en un archivo abierto para leer io.UnsupportedOperation: not writable Usa mode="w" o mode="a"
Usar "w" cuando querías agregar Desaparece todo el contenido anterior Usa "a"
Nombre de archivo sin extensión ("my_file") FileNotFoundError Escribe "my_file.txt"
file.write(5) TypeError: write() argument must be str, not int Convierte: file.write(str(5))
No indicar encoding "Sofía" en lugar de "Sofía" encoding="utf-8"

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1 — Aplicación: crea un programa que pida tu nombre y lo agregue a asistencia.txt, uno por línea. Ejecútalo 3 veces.
  • 🟡 Reto 2 — Ampliación: lee asistencia.txt e imprime cuántas personas hay y la lista numerada.
  • 🟠 Reto 3 — Desafío: agrega la fecha y la hora a cada registro (investiga datetime.now()).
  • 🔴 Reto 4 — Pensamiento computacional: ¿qué pasa si dos personas escriben su nombre con distintas mayúsculas ("ana" y "Ana")? Diseña cómo evitar duplicados antes de escribir.

3. Reto: guardar el récord de la serpiente en un archivo

(Fuente: 184 - Challenge- Read and Write the High Score to a File in Snake.md)

📝 Ejercicio original del curso

Enunciado: crear data.txt con el número 0 y usarlo para que el récord sobreviva al cierre del juego.

🔍 Antes de programar

  • ¿En qué momento hay que leer el archivo? ¿Y en qué momento escribir?
  • read() devuelve un string. ¿Qué necesitas para compararlo con el puntaje?
  • write() solo acepta strings. ¿Cómo guardas un número?

Solución del curso:

Python
# En Scoreboard.__init__ (en lugar de self.high_score = 0):
with open("data.txt") as data:
    self.high_score = int(data.read())

# En Scoreboard.reset(), dentro del if del nuevo récord:
with open("data.txt", mode="w") as data:
    data.write(f"{self.high_score}")

Prueba del curso: logra un récord de 2, detén el programa, vuelve a ejecutarlo… y el récord 2 sigue ahí.

El curso aclara que el mensaje KeyboardInterrupt al pulsar Detener es normal: el juego está hecho para seguir "para siempre".

🛠️ Nota técnica (verificada): esta solución falla en dos situaciones:

  • Si data.txt no existe → FileNotFoundError: [Errno 2] No such file or directory.
  • Si data.txt está vacío → ValueError: invalid literal for int() with base 10: ''.

Ambas son comunes, por ejemplo cuando un compañero descarga tu juego sin el archivo. Por ahora puedes manejarlas con try/except (Día 13). El curso profundiza en el manejo de excepciones en el Día 30.

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: borra data.txt y ejecuta el juego. Anota el error exacto. Luego déjalo vacío y repite.
  • 🟡 Reto 2: maneja ambos errores para que, en esos casos, el récord empiece en 0 y el archivo se cree solo.
  • 🟠 Reto 3: guarda también el nombre del dueño del récord (pídelo con screen.textinput al superarlo).
  • 🔴 Reto 4: guarda los 5 mejores puntajes, uno por línea, ordenados de mayor a menor.

4. Rutas absolutas y relativas

(Fuente: 185 - Understand Relative and Absolute File Paths.md)

🎯 Objetivo de aprendizaje

  • Diferenciar una ruta absoluta de una relativa.
  • Usar ./ y ../ para navegar entre carpetas.

📖 Explicación conceptual

Analogía del curso: un dinosaurio busca un huevo dorado en un mapa. Para darle indicaciones dices: "Sigue hasta el volcán, gira a la derecha en la serpiente, a la izquierda en la palmera…". Una ruta son las indicaciones para llegar a un archivo a través de las carpetas.

Estructura de ejemplo del curso:

Texto
/ (raíz)                   ← en Windows suele ser C:\  ; en Mac, Macintosh HD
└── Work/
    ├── report.doc
    └── Project/
        └── talk.ppt

Ruta absoluta: empieza siempre desde la raíz.

  • /Work/report.doc
  • /Work/Project/talk.ppt
  • En Windows: C:/Users/TuUsuario/Desktop/my_file.txt

Ruta relativa: empieza desde el directorio de trabajo, la carpeta en la que "estás".

Estás en… Quieres llegar a… Ruta relativa
Project talk.ppt ./talk.ppt (o solo talk.ppt)
Work talk.ppt ./Project/talk.ppt
Project report.doc ../report.doc
  • ./ = "en esta carpeta" (se puede omitir).
  • ../ = "sube a la carpeta madre". ../../ sube dos niveles.

📝 Ejercicio original del curso

  1. Mover my_file.txt al Escritorio y buscar su ubicación (clic derecho → Propiedades en Windows; Obtener información en Mac).
  2. Reto A: leerlo con una ruta absoluta, por ejemplo "C:/Users/TuUsuario/Desktop/my_file.txt".
  3. Reto B: leerlo con una ruta relativa desde el proyecto. El proyecto está en .../TuUsuario/PycharmProjects/day-24, así que hay que subir dos niveles hasta la carpeta del usuario y bajar al Escritorio: "../../Desktop/my_file.txt".

Conclusión del curso: ninguna es siempre mejor. Conocer ambas te permite elegir la más adecuada.

🛠️ Notas técnicas (verificadas)

1. Las barras en Windows. El curso dice que en Python se puede escribir / también en Windows, y es cierto. Lo que no se puede es copiar la ruta de Windows tal cual en un string normal:

Python
p = "C:\Users\ana\Desktop\my_file.txt"
# SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes ... truncated \UXXXXXXXX escape

La \ es un carácter de escape (como en \n) y \U inicia un código Unicode. Soluciones: usar /, un string crudo r"C:\Users\ana\..." o duplicar las barras "C:\\Users\\...".

2. ¿Relativa a qué? El curso explica que la ruta relativa parte de la carpeta de main.py. Eso es lo que ocurre en PyCharm, porque ejecuta el programa desde la carpeta del proyecto. En realidad, la ruta relativa parte del directorio de trabajo actual (os.getcwd()), que depende de desde dónde se ejecuta el programa. En VS Code o en la terminal puede ser otra carpeta, y entonces aparece FileNotFoundError aunque el archivo esté "al lado" de main.py. Una forma robusta de construir rutas relativas al archivo del programa:

Python
from pathlib import Path

CARPETA = Path(__file__).parent
with open(CARPETA / "data.txt", encoding="utf-8") as data:
    ...

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: con la estructura Colegio/Grado10/Notas/matematicas.txt, escribe la ruta relativa desde Grado10 y desde Notas hacia Colegio/reglamento.txt.
  • 🟡 Reto 2: imprime os.getcwd() en PyCharm y en la terminal. ¿Coinciden? Explica.
  • 🟠 Reto 3: reescribe el récord de la serpiente usando Path(__file__).parent y ejecuta el juego desde otra carpeta con la terminal.
  • 🔴 Reto 4: investiga os.listdir() o Path.iterdir() y escribe un programa que liste todos los .txt de una carpeta con su tamaño.

5. 🚀 Proyecto del día: la Combinación de Correspondencia (Mail Merge)

(Fuentes: 186 - Introducing the Mail Merge Challenge.md, 187 - Solution & Walkthrough for the Mail Merge Project.md)

Problema

Tienes una carta modelo que dice Dear [name], y una lista de invitados. Debes generar una carta por invitado, reemplazando [name] por su nombre.

Contexto

La "combinación de correspondencia" se usa en la vida real para invitaciones, certificados, circulares para acudientes y correos a clientes. Automatizarla ahorra horas de trabajo repetitivo.

Estructura de carpetas del código inicial del curso

Texto
mail-merge-project-start/
├── main.py
├── Input/
│   ├── Letters/
│   │   └── starting_letter.txt     ← la carta modelo con [name]
│   └── Names/
│       └── invited_names.txt       ← un nombre por línea
└── Output/
    └── ReadyToSend/                ← aquí van las cartas (incluye un archivo de ejemplo)

Los nombres de carpetas y archivos salen de las lecciones 186 y 187. Si tu código inicial tiene nombres ligeramente distintos, ajusta las rutas.

Regla del curso: "sin trampas". No se vale mover archivos a mano: todo se hace con rutas.

Resultado esperado: un archivo letter_for_{nombre}.txt por invitado dentro de ReadyToSend.

Restricciones técnicas

with open(...), rutas relativas y tres métodos que el curso pide investigar en la documentación:

Método Qué hace Ejemplo verificado
readlines() Devuelve una lista con cada línea del archivo ['Aang\n', 'Zuko\n', 'Appa\n']
str.replace(viejo, nuevo) Devuelve un nuevo string con el reemplazo "Me gustan los plátanos".replace("plátanos", "mangos")
str.strip() Quita espacios y saltos de línea al inicio y al final " Hola mundo \n".strip() → "Hola mundo"

Filosofía del curso: es imposible enseñar todos los métodos. Un desarrollador profesional busca la información cuando la necesita, la entiende y la aplica.

🛠️ Nota: en la transcripción aparece "deadline()"; se refiere a readline() (en singular), que lee una línea. Aquí se necesita readlines(), con s, que devuelve todas las líneas.

Planificación

🔍 Antes de programar

  1. Entradas: ¿qué dos archivos se leen? Escribe sus rutas relativas desde main.py.
  2. Proceso: ¿qué se repite para cada nombre?
  3. Salidas: ¿cómo se llama cada archivo generado y en qué carpeta va?
  4. ¿Qué crees que pasará con el \n al final de cada nombre?

Construcción paso a paso (siguiendo la solución del curso)

Versión 1 — Leer los nombres: with open("./Input/Names/invited_names.txt"), primero con read() (un solo string) y luego con readlines() (una lista).

Versión 2 — Leer la carta: constante PLACEHOLDER = "[name]" y letter_contents = letter_file.read(), desde ./Input/Letters/starting_letter.txt.

Versión 3 — Reemplazar: un bucle que crea new_letter = letter_contents.replace(PLACEHOLDER, name) e imprime el resultado.

Versión 4 — El error del salto de línea. Al imprimir, todas las cartas menos la última tienen un salto de línea después del nombre: "Dear Aang" + salto + ",". Es el \n que trae readlines(). La solución es stripped_name = name.strip().

Versión final — Escribir cada carta: with open(f"./Output/ReadyToSend/letter_for_{stripped_name}.txt", mode="w") as completed_letter: y completed_letter.write(new_letter). Como el archivo no existe, el modo "w" lo crea.

🛠️ Nota técnica: en el video de la solución, la carta modelo y las de salida aparecen con extensión .docx, mientras que la introducción habla de archivos .txt. Escribir texto plano en un archivo llamado .docx no crea un documento de Word válido: un .docx real es un paquete comprimido con XML adentro, y Word podría decir que el archivo está dañado. Usa .txt. Para generar documentos de Word de verdad existe la librería python-docx, que no es parte de este día.

Mejora de esta adaptación: agrega encoding="utf-8" a los tres open(). Con nombres como "Sofía" o "Muñoz", sin esto las cartas pueden salir con caracteres extraños (sección 2).

Pruebas

Caso Resultado esperado
Ejecutar el programa Un archivo por nombre en ReadyToSend
Abrir letter_for_Aang.txt Dice "Dear Aang," en la misma línea, sin salto
El último nombre de la lista Su carta es igual a las demás
Agregar "Sofía Muñoz" a la lista Su carta muestra bien la tilde y la ñ
Una línea vacía al final de invited_names.txt ⚠️ ¿Qué archivo se crea? ¿Cómo lo evitas?
Ejecutar desde otra carpeta en la terminal ⚠️ ¿Encuentra los archivos? (nota 2 de la sección 4)

🧪 Prueba y depuración

Este código tiene cuatro errores. Encuéntralos:

Python
PLACEHOLDER = "[nombre]"

with open("./Input/Names/invited_names.txt") as names_file:
    names = names_file.read()

with open("./Input/Letters/starting_letter.txt") as letter_file:
    letter_contents = letter_file.read()
    for name in names:
        new_letter = letter_contents.replace(PLACEHOLDER, name)
        with open(f"./Output/ReadyToSend/letter_for_{name}.txt") as completed_letter:
            completed_letter.write(new_letter)

(Pistas: un marcador que no coincide con la carta; recorrer un string en vez de una lista (¿qué es name en cada vuelta?); falta un strip; y un modo de apertura.)

⭐ Extensión del proyecto

  • Varios marcadores: [name], [date], [place].
  • Una lista de invitados con dos columnas: nombre,apodo.
  • Un resumen al final: "Se generaron 7 cartas".

6. 🌟 Proyecto extra: la Bitácora del Huerto Escolar

Situación

El proyecto ambiental del colegio tiene un huerto. Cada día, un estudiante registra la temperatura, si se regó y una observación. Hoy lo anotan en un cuaderno que se pierde.

Requisitos

  1. Un menú en la consola: 1. Registrar día, 2. Ver resumen, 3. Salir.
  2. Registrar agrega una línea a bitacora/AAAA-MM.txt (un archivo por mes, dentro de la carpeta bitacora) con el formato fecha;temperatura;regado;observación.
  3. Si la carpeta no existe, el programa la crea (investiga os.makedirs con exist_ok=True o Path.mkdir).
  4. Ver resumen lee el archivo del mes y muestra: días registrados, temperatura promedio, días sin riego y la última observación.
  5. Valida los datos: la temperatura debe ser un número entre −5 y 45, y el riego "si" o "no".
  6. Usa encoding="utf-8" y rutas construidas con Path(__file__).parent.

Decisiones que debes tomar

  • ¿Qué modo de apertura usas para registrar? ¿Y para leer?
  • ¿Por qué separar los campos con ; y no con ,? (Piensa en las observaciones.)

Reflexión

¿Qué ventajas tiene un archivo por mes frente a un único archivo gigante?


7. 🏆 Proyecto integrador del Día 24: Generador de Informes para Acudientes

Proyecto integrador creado para esta adaptación. Integra archivos, modos de apertura, rutas, métodos de strings, diccionarios (Día 9), funciones (Días 8 y 10), validación y manejo de errores (Día 13).

Situación problema

Al final de cada periodo, el director de grupo escribe a mano una nota para el acudiente de cada estudiante. Quiere automatizarlo con una plantilla y los datos de cada estudiante.

Pregunta orientadora

¿Cómo diseñar un programa que transforme datos en documentos personalizados, de forma confiable, sin mover archivos a mano?

Requerimientos

  1. Entradas en entrada/:
    • plantilla.txt, con los marcadores [acudiente], [estudiante], [promedio], [desempeno] y [mensaje].
    • estudiantes.txt, con una línea por estudiante: estudiante;acudiente;nota1;nota2;nota3.
  2. Para cada estudiante:
    • Calcular el promedio (con un decimal).
    • Determinar el desempeño según la escala de tu institución (por ejemplo: Bajo, Básico, Alto, Superior).
    • Elegir un mensaje según el desempeño, guardado en un diccionario.
    • Generar salida/informes/informe_{estudiante}.txt, sin espacios en el nombre del archivo (reemplázalos por _).
  3. Si una línea tiene un error (faltan datos o una nota no es un número), no se detiene: la escribe en salida/errores.txt con el número de línea y continúa.
  4. Al final, genera salida/resumen.txt con el total de informes, el promedio del grupo y la cantidad de estudiantes por desempeño.
  5. Rutas con Path(__file__).parent, encoding="utf-8" en todos los archivos y funciones con docstring.

Etapas de desarrollo

  1. Leer y mostrar los datos en la consola.
  2. Un informe correcto para un estudiante.
  3. Todos los informes.
  4. Manejo de líneas con errores.
  5. Resumen del grupo.

Entregables

  • El código y las carpetas entrada/ y salida/ con un ejemplo de al menos 8 estudiantes ficticios (dos de ellos con errores a propósito).
  • Una explicación de la estructura de carpetas y las rutas usadas.

Casos de prueba

Caso Esperado
Estudiante "María José Peña" Archivo informe_María_José_Peña.txt con tildes correctas
Línea con la nota "cuatro" Registrada en errores.txt; el programa continúa
Línea con solo 2 campos Registrada en errores.txt
Ejecutar dos veces Los informes se reemplazan, no se duplican
Ejecutar desde otra carpeta Funciona igual

Criterios técnicos

  • Ningún open() sin with.
  • Ninguna ruta absoluta en el código.
  • Cambiar la plantilla no exige tocar el código.

⚠️ Protección de datos: usa nombres ficticios. Los datos reales de estudiantes y acudientes son información personal protegida.


8. 🧩 Comprueba lo aprendido

Conceptuales

  1. ¿Qué diferencia hay entre los modos "w" y "a"?
  2. ¿Por qué se prefiere with open(...) a open() con close()?
  3. ¿De qué depende una ruta relativa?

Análisis de código

Python
with open("notas.txt", mode="w") as f:
    f.write("5")
with open("notas.txt", mode="w") as f:
    f.write("4")
with open("notas.txt") as f:
    print(f.read())

¿Qué imprime? ¿Y si el segundo modo fuera "a"?

Predicción

Estás en Colegio/Grado10/Proyecto/. ¿A qué archivo apunta "../../Rectoria/circular.txt"?

Depuración

Python
with open("data.txt") as data:
    high_score = data.read()
if 7 > high_score:
    print("¡Nuevo récord!")

¿Qué error aparece y por qué?

Modificación

Cambia el Mail Merge para que los archivos de salida se llamen invitacion_{nombre}_{fecha}.txt, con la fecha de hoy.

Creación

Escribe un programa que cuente cuántas veces aparece cada palabra en un archivo texto.txt y guarde el resultado en conteo.txt, una palabra por línea.


9. 🤖 Programar con apoyo de IA

Actividad: comprobar afirmaciones sobre archivos.

  1. Pregunta a una IA: "¿Una ruta relativa en Python es relativa a la ubicación del archivo .py?". Anota su respuesta.
  2. Compruébalo tú: imprime os.getcwd() y ejecuta el mismo programa desde dos carpetas distintas en la terminal. ¿La IA tenía razón?
  3. Pídele el código del Mail Merge. ¿Incluye encoding="utf-8"? Pruébalo con un nombre con tilde en Windows.
  4. Consulta la documentación oficial de open() (se abre en otra pestaña) y verifica qué dice sobre la codificación por defecto.
  5. Escribe en tu cuaderno qué afirmación de la IA verificaste y con qué fuente.

10. 🛠️ Correcciones técnicas al material original

Archivo Afirmación o comportamiento del curso Observación Tratamiento
183 open() sin indicar la codificación En Windows, un archivo UTF-8 con "Sofía" se lee como "Sofía" (verificado con cp1252) Nota técnica del Tema 2
184 int(data.read()) Falla si el archivo no existe (FileNotFoundError) o está vacío (ValueError) (verificado) Nota técnica del Tema 3
185 La ruta relativa parte de la carpeta de main.py Parte del directorio de trabajo actual; en PyCharm coinciden, en otros entornos no Nota técnica 2 del Tema 4
185 En Python se puede escribir / en Windows Correcto; pero copiar C:\Users\... en un string normal da SyntaxError (verificado) Nota técnica 1 del Tema 4
187 Carta modelo y cartas de salida .docx Texto plano con extensión .docx no es un documento de Word válido; usar .txt Nota técnica del proyecto
187 "deadline()" Error de transcripción: readline(); el proyecto usa readlines() Nota del proyecto
182 Los segmentos viejos se envían a (1000, 1000) Funciona, pero siguen en memoria; hideturtle() es una alternativa Análisis del Tema 1

11. 📋 Matriz de trazabilidad

Contenido original Archivo de origen Concepto desarrollado Ejercicio original Reto adicional Proyecto relacionado
Objetivos: récord y Mail Merge 181 Sección 0 — — Secciones 1 y 5
Récord, reset de marcador y serpiente, estado que se pierde 182 Tema 1 Récord en memoria — Tema 3
open, read, write, close, with, modos 183 Tema 2 my_file.txt y new_file.txt Retos 1–4 del Tema 2 Secciones 5, 6 y 7
Récord en data.txt 184 Tema 3 Leer y escribir el récord Retos 1–4 del Tema 3 —
Rutas absolutas y relativas, ./, ../ 185 Tema 4 Archivo en el Escritorio Retos 1–4 del Tema 4 Secciones 5, 6 y 7
Mail Merge: planteamiento 186 Sección 5 Enunciado y estructura Análisis previo Sección 7
Mail Merge: readlines, replace, strip 187 Sección 5 Solución completa Depuración y extensiones Sección 7
No hay una solución correcta; legibilidad 188 Sección 0 — — Criterios de los proyectos
(No existe en el curso original) — — — Bitácora del Huerto Escolar Sección 6
(No existe en el curso original) — — — Informes para Acudientes Sección 7

12. 📦 Evidencias de aprendizaje del Día 24

  • Juego de la serpiente con récord persistente y captura del récord después de reiniciar el programa.
  • Mail Merge funcionando, con captura de la carpeta ReadyToSend y de una carta.
  • Un esquema de carpetas con 3 rutas absolutas y 3 relativas escritas por ti.
  • Prueba de la codificación: captura de "Sofía" leída sin y con encoding="utf-8".
  • Proyecto extra (Bitácora del Huerto) o integrador (Informes para Acudientes).
  • Cuaderno de errores: FileNotFoundError, UnsupportedOperation: not writable, ValueError con int(""), TypeError al escribir un número, SyntaxError por \U en rutas de Windows, el \n de readlines() y las tildes dañadas.