UdelaR  ·  Máster en Análisis de Datos

Introducción a Python

Clase 1 — ¿Qué es un programa?

Asignatura  Introducción a Python Profesor  Daniel Miles Touya Universidad  UdelaR-Uvigo
Parte I

¿Para qué aprender a programar si existe la IA?

La pregunta incómoda debate

Hoy la IA escribe código funcional en segundos. ChatGPT, GitHub Copilot, Claude generan scripts de Python a partir de una frase en español. En ese contexto, la pregunta es legítima: ¿tiene sentido dedicar tiempo a aprender Python?

  1. ¿Qué diferencia hay entre usar una herramienta y depender de ella? Piensa en un ejemplo fuera de la programación.
  2. Si la IA genera 100 líneas de Python para analizar tus datos, ¿cómo sabes si el resultado es correcto? ¿Qué necesitas saber para comprobarlo?
  3. ¿Qué habilidad nueva ha creado la IA que antes no era necesaria en pogramación?
Respuesta orientativa
a

Usar una calculadora sin entender aritmética es un ejemplo clásico: puedes obtener resultados, pero no detectas errores ni sabes cuándo el resultado es absurdo. Lo mismo ocurre con conducir usando solo GPS: funciona hasta que el GPS falla o te lleva a un camino cortado.

b

Para verificar código necesitas entender qué hace cada parte: qué datos entran, qué transformaciones se aplican, qué sale. Sin leer el código no puedes distinguir un error silencioso (que produce un número incorrecto sin avisar) de un resultado correcto.

Clave: la IA no elimina la necesidad de entender código. La traslada: ya no necesitas escribirlo, pero sí leerlo y supervisarlo.
c

La IA ha creado la habilidad de supervisar código generado automáticamente. Antes había una barrera alta para producir código. Ahora esa barrera ha desaparecido, pero ha aparecido una nueva: saber si el código que te dan es correcto. El que sabe leerlo tiene ventaja sobre el que no.

La analogía del traductor automático práctica

Abre DeepL y traduce la siguiente frase al ruso.

"La muestra presenta un sesgo significativo en la estimación del error estándar."

  1. Sin saber ruso, ¿cómo sabemos que la traducción es correcta?
  2. ¿Qué criterio usarías para confiar en ella?
  3. Los términos muestra, sesgo y significativo tienen significados técnicos precisos en estadística. ¿Qué riesgo hay si el traductor los vierte por su equivalente cotidiano en ruso en lugar del término técnico?
  4. ¿En qué se parece esta situación a pedirle a la IA que escriba un script de Python para analizar tus datos y ejecutarlo sin leerlo?
Respuesta orientativa
a

La traducción inversa de la traducción al ruso a veces devolve algo como "El ejemplo tiene un gran desplazamiento en el cálculo del error típico." Suena coherente, pero ha perdido el significado técnico: muestra se convierte en "ejemplo", sesgo en "desplazamiento" y significativo en "grande". Ninguna de esas sustituciones es incorrecta en ruso cotidiano, pero todas son incorrectas en contexto estadístico.

b

Sin saber ruso, no puedes saberlo. Puedes confiar en que DeepL es una herramienta potente, pero no puedes verificar si ha elegido el término técnico correcto o el cotidiano. La confianza ciega en la herramienta no es un criterio: es una apuesta.

Clave: una traducción puede ser fluida, gramaticalmente correcta y completamente errónea en su significado técnico. Lo mismo ocurre con el código generado por IA: puede ejecutarse sin errores y producir resultados incorrectos.
c

El riesgo es que el lector ruso entienda algo diferente a lo que el autor quería decir, sin que ninguno de los dos lo detecte. En estadística, confundir sesgo con "desplazamiento genérico" o muestra con "ejemplo" invalida cualquier conclusión que se extraiga del análisis.

d

La analogía es directa: la IA es un traductor que genera código que parece correcto, se ejecuta sin errores y produce un número. Pero si no lees el código no sabes si está calculando lo que tú necesitas o algo sutilmente distinto. Igual que con la traducción, el error no es visible en la superficie.

Conclusión: usar la IA para escribir código es como usar DeepL para traducir al ruso. Puedes obtener un resultado. Pero sin conocer la estructura y la sintáxis del lenguaje no puedes saber si es correcto.
El error que no aparece: implementación vs concepto debate

Un analista necesita predecir las ventas mensuales de productos de limpieza de una cadena de supermercados. Le pide a la IA un modelo de predicción. En 1 segundo obtiene este código, que corre sin ningún error:

import pandas as pd
from chronos import ChronosPipeline
import torch

# Cargar serie de ventas mensuales
df = pd.read_csv("ventas_limpieza.csv", parse_dates=["fecha"])
serie = torch.tensor(df["ventas"].values, dtype=torch.float32)

# Cargar modelo Chronos preentrenado
pipeline = ChronosPipeline.from_pretrained("amazon/chronos-t5-small")

# Predecir los próximos 6 meses
forecast = pipeline.predict(serie, prediction_length=6)
median = forecast[0].median(dim=0).values

print(f"Predicción próximos 6 meses: {median.tolist()}")

El modelo produce una curva suave con un RMSE razonable. El gráfico parece profesional. No hay ningún mensaje de error ni advertencia. Tres meses después, las predicciones se alejan sistemáticamente de las ventas reales: el modelo no capturó los cambios estacionales de los repuntes de enero, la caída de agosto ni el pico de primavera.

  1. El código no tiene ningún error de sintaxis y el modelo corre perfectamente. ¿Dónde está entonces el problema? ¿Qué tipo de error es este?
  2. Chronos es un modelo de foundation preentrenado en millones de series temporales genéricas. ¿Qué información sobre tus datos necesitarías tener clara antes de elegir este modelo?
  3. La IA generó el código en menos de un segundo y funciona. ¿Qué pregunta debería haberse hecho el analista antes de pedirle el código a la IA?
  4. ¿Qué diferencia hay entre un modelo que funciona y un modelo que es correcto para tu problema?
Respuesta orientativa
a

El problema no es de implementación sino conceptual. El código hace exactamente lo que se le pidió: aplica Chronos a la serie y produce una predicción. El error está en que el modelo elegido no es adecuado para esta serie concreta. Esto es un error de nivel 2: no produce ningún mensaje, no interrumpe la ejecución, y solo se detecta comparando las predicciones con la realidad.

Distinción clave: un error de nivel 1 (sintaxis, función mal llamada) lo detecta la IA y lo corrige sola. Un error de nivel 2 (modelo inadecuado, pregunta mal formulada) es invisible para la IA porque el código es correcto. Solo lo detectas si entiendes qué hay detrás del modelo.
b

Antes de elegir el modelo necesitas saber: ¿tiene la serie estacionalidad propia de este negocio? ¿Cuántos datos históricos hay? ¿El patrón es estable o ha cambiado en los últimos años? ¿Qué eventos externos afectan las ventas (promociones, festivos, cambios de precio)? Chronos no conoce ninguna de estas particularidades: fue entrenado en series genéricas y aplana los patrones que no están en su prior.

c

La pregunta previa debería ser: ¿qué estructura tienen mis datos y qué tipo de modelo es adecuado para esa estructura? La IA responde muy bien a "dame código para predecir con Chronos". Responde mucho peor a "¿qué modelo debo usar para esta serie y por qué?" porque esa pregunta requiere conocimiento del negocio que la IA no tiene.

El problema del hacer: la IA ha eliminado la barrera de implementar. Pero eso desplaza todo el peso hacia los conceptos: ahora el único obstáculo es saber qué estás pidiendo y si tiene sentido pedirlo.
d

Un modelo que funciona produce un resultado sin errores. Un modelo correcto produce un resultado que responde a la pregunta que realmente te estás haciendo. Son dos cosas completamente distintas.

Antes de la IA, ambas barreras existían: había que saber programar y había que saber qué se estaba calculando. La dificultad técnica actuaba como filtro natural — quien llegaba a producir un resultado había invertido suficiente tiempo como para entender, al menos parcialmente, lo que hacía.

La IA ha eliminado ese filtro. Ahora cualquiera puede obtener un resultado en segundos. Pero eso no significa que el resultado sea el correcto: significa que la barrera técnica ha desaparecido y ha dejado expuesta, sin protección, la barrera conceptual.

Esa barrera conceptual siempre estuvo ahí. La diferencia es que antes era la segunda dificultad. Ahora es la única. Y es la más difícil porque no produce mensajes de error, no interrumpe la ejecución y no tiene solución automática. Requiere que el analista sepa qué pregunta está haciendo, qué hipótesis asume el modelo que está usando, y si esas hipótesis son razonables para sus datos.

Consecuencia directa: con la IA, el valor del analista de datos ya no está en saber escribir código. Está en saber qué código pedir, por qué, y cómo verificar que el resultado tiene sentido. Eso exige dominar los conceptos teóricos detrás de cada técnica: qué asume un modelo ARIMA, en qué contextos falla XGBoost, por qué Chronos no es adecuado para series con estacionalidad específica de negocio. Sin esa base, la IA es una herramienta que produce resultados con aspecto profesional y error invisible.
Los conceptos teóricos claros juegan un rol fundamental en el trabajo con la IA. No como requisito para escribir código, sino como requisito para saber si el código que la IA escribe tiene sentido. La teoría no ha quedado obsoleta con la IA: se ha vuelto el único recurso que la IA no puede sustituir.
¿Qué nos queda? La pregunta que nadie quiere responder debate

En noviembre de 2025, Dario Amodei — CEO de Anthropic, la empresa que construye Claude, la IA que estáis usando en este curso — advirtió en una entrevista con 60 Minutes que la IA podría eliminar hasta la mitad de los empleos de nivel inicial en consultoría, derecho y finanzas en un plazo de uno a cinco años. Añadió que el impacto será más rápido que cualquier cambio tecnológico anterior. Como dato concreto: Anthropic ya reveló que Claude escribe el 90% del código de la propia empresa.

▶ Ver entrevista — 60 Minutes · nov 2025
  1. Amodei menciona explícitamente a consultores, abogados y profesionales financieros de nivel inicial. ¿En qué se parece ese perfil al vuestro al salir de este máster? ¿Qué tareas concretas de ese trabajo creéis que ya puede hacer la IA hoy?
  2. Si la IA puede escribir código, resumir informes, limpiar datos, ajustar modelos y generar visualizaciones, ¿qué queda que no pueda hacer? Intentad ser específicos: no vale decir "la creatividad" o "el factor humano" sin concretar qué significa eso en vuestro trabajo diario.
  3. Hay una diferencia entre tareas que la IA ejecuta y decisiones que alguien tiene que tomar. ¿Dónde está esa frontera en el análisis de datos? ¿Quién decide qué pregunta hacer, qué modelo es adecuado, si el resultado tiene sentido para el negocio?
  4. Dado todo esto: ¿qué estáis construyendo realmente en este curso? ¿Es aprender Python, o es algo distinto?
Orientación para el debate
a

Un analista de datos junior típicamente limpia datos, ajusta modelos estándar, genera informes y presenta resultados. La IA ya hace todo eso. Lo que no hace es decidir qué datos recoger, qué pregunta merece ser respondida, ni si el resultado tiene implicaciones que el cliente no había anticipado. Esas tareas requieren conocimiento del contexto, del negocio y de las limitaciones del método — no solo de la herramienta.

b

Lo que queda no es abstracto. Son cosas muy concretas:

Saber qué pregunta hacer. La IA responde preguntas con precisión creciente, pero no sabe cuál es la pregunta relevante para tu negocio, tu cliente o tu investigación. Esa es siempre una decisión humana.

Evaluar si el resultado tiene sentido. Un modelo puede producir un número perfecto que responde a la pregunta equivocada. Detectar eso requiere entender el método, los datos y el contexto simultáneamente.

Asumir la responsabilidad del resultado. Cuando un análisis informa una decisión empresarial o política, alguien tiene que firmar debajo. La IA no firma. No asume consecuencias. No responde ante un comité de ética ni ante un cliente insatisfecho.

Lo que queda: juicio, criterio y responsabilidad. Las tres cosas que la IA no puede tener porque no tiene ningún interés en el resultado.
c

La frontera está exactamente ahí: entre ejecutar y decidir. La IA ejecuta con una eficiencia que ningún humano puede igualar. Pero cada ejecución empieza con una decisión que alguien tomó antes: qué variable es la dependiente, qué período temporal es relevante, qué modelo asume qué hipótesis, qué significa "bueno" en este contexto.

Esas decisiones no son técnicas. Son conceptuales. Y para tomarlas bien hay que entender qué hay detrás de cada técnica: qué asume, cuándo falla, qué no ve. Sin esa base, delegar en la IA no es eficiencia: es abdicación.

El riesgo real: no es que la IA os sustituya. Es que os sustituyamos vosotros mismos delegando decisiones que solo vosotros podéis tomar, porque solo vosotros conocéis el contexto, el cliente y lo que está en juego.
d

Este curso no es sobre Python. Python es el medio. Lo que estáis construyendo es la capacidad de leer lo que la IA produce, entender si tiene sentido, y tomar decisiones informadas sobre si usarlo, corregirlo o descartarlo.

Eso requiere dos cosas que este máster os da y que la IA no puede darse a sí misma: los conceptos teóricos detrás de las técnicas, y el criterio para aplicarlos en contextos reales con incertidumbre, datos imperfectos y preguntas mal definidas.

La respuesta a Amodei: lo que os queda no es competir con la IA en velocidad de ejecución. Es hacer las preguntas que la IA no puede hacerse, evaluar las respuestas que la IA no puede evaluar, y asumir la responsabilidad que la IA no puede asumir. Eso no desaparece. Al contrario: se vuelve lo único que importa.
Parte II

El intérprete: Python como conversación

El intérprete: predecir antes de ejecutar práctica

Abre Google Colab — no se instala nada. Para cada bloque de abajo, escribe tu predicción antes de ejecutar. No importa equivocarse: el objetivo es aprender a razonar sobre el código, no adivinar correctamente.

— Tanda 1: operaciones básicas —

2 + 2
"2" + "2"
10 / 3
10 // 3
type(42)
type("hola")

— Tanda 2: una función anónima —

# ¿Qué hace esto? Razona antes de ejecutar.
cuadrados = list(map(lambda x: x**2, [0, 1, 2, 3, 4]))
print(cuadrados)

— Tanda 3: el intérprete escucha —

# ¿En qué se diferencia esta línea de todas las anteriores?
nombre = input("¿Cómo te llamas? ")
print(f"Hola, {nombre}. Bienvenido a Python.")
  1. 2 + 2 devuelve 4. "2" + "2" devuelve "22". El símbolo + es el mismo — ¿qué ha cambiado? ¿Qué te dice esto sobre cómo lee Python lo que escribes?
  2. Mira la línea del lambda. Sin saber todavía qué significa esa palabra, ¿puedes deducir qué hace lambda x: x**2 a partir del resultado que produce? ¿Y qué hace map?
  3. El bloque del input se comporta de forma distinta a todos los anteriores: no produce un resultado inmediato, sino que espera. ¿Qué diferencia fundamental introduce esto? ¿En qué convierte al intérprete?
  4. Hasta ahora hemos usado el intérprete para verificar expresiones aisladas. Si la IA te genera un bloque de 20 líneas, ¿cómo podrías usar esta misma idea para entender qué hace antes de ejecutarlo entero?
Respuesta orientativa
a

Lo que ha cambiado es el tipo. Con 2 + 2 Python ve dos enteros y aplica la suma aritmética. Con "2" + "2" ve dos cadenas de texto y aplica concatenación. El símbolo + no tiene un significado fijo: su comportamiento depende del tipo de los objetos sobre los que actúa. Esto se llama sobrecarga de operadores.

Clave de lectura: cuando leas código ajeno, antes de interpretar un operador pregúntate qué tipo tienen los datos sobre los que actúa. El mismo símbolo puede hacer cosas completamente distintas.
b

lambda x: x**2 es una función sin nombre que toma un valor x y devuelve su cuadrado. map aplica esa función a cada elemento de la lista [0, 1, 2, 3, 4] uno a uno. El resultado es [0, 1, 4, 9, 16].

Lo interesante no es memorizar la sintaxis del lambda ahora mismo, sino notar que podías deducir qué hacía mirando el resultado y razonando hacia atrás. Esa es exactamente la habilidad de lectura de código que estamos construyendo en este curso.

c

El input convierte el intérprete en una conversación bidireccional: ya no solo Python responde a lo que tú escribes, sino que Python te pregunta algo y espera tu respuesta antes de continuar. El programa tiene ahora un estado que depende de lo que ocurra en tiempo de ejecución, no solo de lo que está escrito en el código.

El intérprete como conversación: cada línea que escribes es un turno. Python responde, tú lees, decides el siguiente turno. Con la IA ese mismo bucle ocurre a otro nivel: la IA propone código, tú lo lees y decides si ejecutarlo, modificarlo o descartarlo. El intérprete es la herramienta con la que verificas cada propuesta de la IA antes de aceptarla.
d

Exactamente así: en lugar de ejecutar las 20 líneas de golpe, las cortas en fragmentos y ejecutas cada uno por separado. Primero verificas que los datos entran bien, luego que la primera transformación produce lo que esperas, luego la segunda. Si algo falla, sabes exactamente en qué paso.

Este hábito — fragmentar y verificar antes de ejecutar en bloque — es la diferencia entre usar el intérprete como herramienta de comprensión y usarlo solo como herramienta de ejecución.

Con la IA especialmente: el código generado automáticamente tiende a ser denso y compacto. Fragmentarlo y ejecutarlo por partes es la única forma de entender qué hace cada pieza antes de confiar en el resultado final.
Sintaxis: no vale cualquier forma de conversar práctica

El intérprete de Python es conversacional, pero no es indulgente. Para cada bloque de abajo sigue estos tres pasos:

  1. Predice — antes de ejecutar, mira el código e intenta adivinar qué tipo de error producirá y por qué.
  2. Ejecuta — cópialo en Colab y ejecútalo. Lee con atención el mensaje de error completo.
  3. Interpreta — ¿el mensaje te dice exactamente dónde está el problema? ¿Coincide con tu predicción?

— Error 1: algo falta —

print("hola"   # copia tal cual

— Error 2: tipos incompatibles —

"hola" + 3   # ¿por qué falla si + funciona con strings?

— Error 3: algo no está definido —

print(resultado)   # ¿qué no sabe Python aquí?

— Error 4: el espacio importa —

if True:
print("hola")   # ¿qué tiene de especial el espacio en Python?
  1. Para cada error: ¿qué nombre le da Python al error en el mensaje de Colab? ¿En qué línea señala el problema? ¿El mensaje es suficiente para entender qué hay que corregir sin saber Python?
  2. Los errores 1 y 4 los detecta Python antes de ejecutar ninguna instrucción. Los errores 2 y 3 los detecta durante la ejecución. ¿Qué diferencia práctica tiene esto cuando el programa tiene 100 líneas en lugar de 1?
  3. El error 4 sorprende a quien viene de otros lenguajes. En Python el espaciado no es decorativo: es parte de la sintaxis. Fíjate en el mensaje que produce Colab — ¿qué nombre le da Python a este tipo de error?
  4. Ninguno de estos cuatro errores es el más peligroso en la práctica. ¿Por qué? ¿Qué tipo de error sería peor que todos estos y cómo se relaciona con lo que vimos en la Parte I?
Respuesta orientativa
a

Python nombra cada tipo de error con precisión: el error 1 es un SyntaxError — la estructura de la frase es incorrecta, como en castellano escribir "al muerde perro hombre el": las mismas palabras, pero en un orden que ningún hablante puede procesar. El error 2 es un TypeError — los tipos son incompatibles para esa operación. El error 3 es un NameError — Python no encuentra en su memoria ningún objeto llamado resultado porque nunca se definió. El error 4 es un IndentationError — la jerarquía visual del código no está respetada.

Clave de lectura: el nombre del error es lo primero que hay que leer en un mensaje de Colab. Ya antes de leer el resto del mensaje, el nombre te dice en qué categoría está el problema: estructura, tipos, memoria o jerarquía.
b

Si el programa tiene 100 líneas y el error ocurre antes de ejecutar (SyntaxError, IndentationError), el programa no arranca en absoluto — sabes de inmediato que algo está mal y dónde está. Si el error ocurre durante la ejecución (TypeError, NameError), el programa puede haber ejecutado 80 líneas correctamente antes de fallar — lo que ya hizo no se deshace.

En un pipeline de datos esto es especialmente relevante: si el error ocurre en la línea 90, los datos ya fueron leídos, filtrados y transformados por las 89 líneas anteriores. El error no contamina esos pasos, pero tampoco los completa.

c

Python llama a este error IndentationError. En castellano usamos el punto y aparte o la sangría para señalar que empieza una unidad nueva de sentido. Python usa la sangría con el mismo propósito estructural, pero de forma obligatoria: indica qué instrucciones pertenecen a un bloque y cuáles están fuera de él.

La ventaja para la lectura es directa: la estructura lógica del programa es visible en la estructura visual del código. Antes de entender qué hace cada línea, la indentación ya te dice cómo se relacionan entre sí. En Python, la forma del código refleja su lógica.

d

Todos estos errores son visibles: producen un mensaje, interrumpen la ejecución, señalan una línea. El error verdaderamente peligroso es el que no produce ningún mensaje: el código ejecuta, produce un número, y ese número es incorrecto sin que nadie lo advierta.

Es exactamente lo que vimos en la Parte I con Chronos: el modelo ejecutó sin errores, produjo una predicción, y esa predicción era incorrecta porque el modelo era inadecuado para esos datos. Python no puede detectar ese error porque la sintaxis era perfecta y los tipos eran compatibles. Solo lo detecta quien entiende qué debería haber producido el código.

Conclusión: aprender a leer código no es solo aprender a evitar SyntaxError. Es desarrollar el criterio para detectar el error que no tiene nombre, no interrumpe la ejecución y no aparece en ningún mensaje de Colab.
Parte III

Leer un programa real sin saber Python

Hasta ahora hemos usado Python de forma interactiva: escribimos una expresión, Python responde, escribimos otra. Es útil para explorar y verificar, pero no es como se usa Python en la práctica.

Lo más habitual es escribir todas las instrucciones juntas en un fichero — un script — y dárselo a Python para que lo lea de arriba a abajo y ejecute cada instrucción en orden. En lugar de una conversación turno a turno, es más parecido a entregarle una carta con instrucciones: Python la lee entera y hace lo que dice.

En esta parte vamos a leer un script real completo por primera vez. El objetivo no es entender cada línea: es aprender a orientarse en un programa que no has visto nunca.

El programa de las notas lectura

Lee el programa completo de abajo sin ejecutarlo. No importa que no entiendas cada palabra. Intenta deducir qué hace mirando los nombres de las funciones, las variables y los print del final.

import csv
from pathlib import Path

def cargar_notas(ruta):
    notas = []
    with open(ruta) as f:
        lector = csv.DictReader(f)
        for fila in lector:
            notas.append(float(fila["nota"]))
    return notas

def calcular_estadisticas(notas):
    n = len(notas)
    media = sum(notas) / n
    aprobados = [x for x in notas if x >= 5]
    tasa = len(aprobados) / n * 100
    return media, tasa

ruta = Path("notas.csv")
notas = cargar_notas(ruta)
media, tasa_aprobados = calcular_estadisticas(notas)

print(f"Media: {media:.2f}")
print(f"Aprobados: {tasa_aprobados:.1f}%")
  1. ¿Cuántas funciones tiene el programa? ¿Cómo se llaman y qué crees que hace cada una?
  2. ¿Dónde empieza a ejecutarse el programa? (No en la primera línea.) ¿Cómo lo sabes?
  3. Sin saber Python: ¿qué imprimirá el programa al final? ¿Qué información mostrará?
  4. La línea aprobados = [x for x in notas if x >= 5] es sintaxis que no has visto. Aun así, ¿qué crees que hace? ¿Qué te lleva a esa conclusión?
Respuesta orientativa
a

Hay dos funciones. cargar_notas parece leer un fichero CSV y extraer los valores de la columna "nota". calcular_estadisticas parece calcular la media y el porcentaje de aprobados a partir de esas notas.

b

El programa empieza a ejecutarse en la línea ruta = Path("notas.csv"), que es la primera que está fuera de cualquier función (sin indentación bajo un def). Las definiciones de funciones se leen pero no se ejecutan hasta que se las llama.

Clave de lectura: el código con def define; el código sin sangría al final es el que manda ejecutar.
c

Imprimirá dos líneas: la nota media de todos los alumnos (con 2 decimales) y el porcentaje de aprobados (con 1 decimal). Por ejemplo: Media: 6.34 y Aprobados: 72.5%.

d

La expresión construye una lista con los elementos de notas que cumplen la condición x >= 5. Aunque la sintaxis sea nueva, las palabras inglesas for, in e if dan suficientes pistas. Esto se llama list comprehension y es una de las construcciones más frecuentes en Python real.

Otro programa: ¿qué hace? lectura

Lee el programa de abajo sin ejecutarlo. No importa que no entiendas cada palabra. Intenta deducir qué hace mirando su estructura, los nombres que aparecen y lo que produce al final.

import csv
from pathlib import Path

stats = lambda d: (lambda n, s, a: (s/n, len(a)/n*100))(len(d), sum(d), list(filter(lambda x: x>=5, d)))
parse = lambda f: list(map(lambda r: float(r["nota"]), csv.DictReader(f)))

with open(Path("notas.csv")) as f:
    m, t = stats(parse(f))

[print(f"{a}: {b:.{c}f}") for a, b, c in zip("mn", [m, t], [2, 1])]
  1. ¿Cuántas funciones tiene el programa? ¿Cómo se llaman? ¿Puedes deducir qué hace cada una a partir de su nombre?
  2. ¿Dónde empieza a ejecutarse el programa? ¿Puedes seguir el hilo de ejecución como en el programa anterior?
  3. ¿Qué crees que produce al final? ¿Puedes deducirlo mirando la última línea?
  4. ¿Qué es lo que más dificulta la lectura de este programa respecto al anterior? Intenta ser concreto.
Respuesta orientativa
a

Hay dos funciones: stats y parse. A diferencia del programa anterior, los nombres no dicen nada sobre lo que hacen — parse es genérico y stats es una abreviatura que no aclara qué estadísticas calcula ni sobre qué datos. Un nombre como cargar_notas se lee; un nombre como parse hay que descifrar.

b

El programa empieza a ejecutarse en el bloque with open(...), que es la primera instrucción fuera de las definiciones. Pero seguir el hilo es mucho más difícil: stats(parse(f)) encadena dos funciones en una sola línea, y para entender qué hace hay que desenrollar mentalmente cada una por separado antes de poder ver el conjunto.

c

La última línea es la más opaca del programa. Usa letras sueltas sin significado (a, b, c), y un print dentro de una list comprehension — una construcción pensada para construir listas, no para imprimir. Es prácticamente imposible deducir qué imprime sin ejecutarlo.

Revelación: este programa produce exactamente el mismo resultado que el programa anterior. Las mismas dos líneas, los mismos valores, el mismo formato. Son dos formas de escribir lo mismo — una pensada para ser leída, la otra no.
d

Lo que más dificulta la lectura son tres cosas acumuladas: nombres sin significado, operaciones comprimidas en una sola línea, y estructuras usadas fuera de su propósito habitual. Cada una por separado sería tolerable; las tres juntas hacen el código opaco.

Esta no es una situación académica. El código generado por IA tiende a ser compacto y técnicamente correcto, pero no siempre legible. Reconocer cuándo un código es innecesariamente opaco — y saber pedir una versión más clara — es una habilidad tan importante como leer el código en sí.

Los creadores de Python lo convirtieron en filosofía. Escribe import this en cualquier intérprete y verás los 19 principios del Zen de Python. Los más relevantes para lo que acabamos de ver:

Readability counts. La legibilidad importa.

Explicit is better than implicit. Explícito es mejor que implícito.

Sparse is better than dense. Disperso es mejor que denso.

If the implementation is hard to explain, it's a bad idea. Si la implementación es difícil de explicar, es una mala idea.

El programa anterior cumple los cuatro. Este los viola todos. Python permite escribirlo porque la sintaxis es correcta. Pero su propia filosofía lo desaconseja.

Parte IV

Pseudo-codigos

¿Qué es un pseudocódigo? reflexión

Antes de escribir código — o de pedirle código a la IA — hay que saber qué se quiere hacer. Eso parece obvio, pero en la práctica es la parte que más se saltea.

El pseudocódigo es una forma de escribir la lógica de un programa en lenguaje natural estructurado: sin sintaxis de Python, sin preocuparse por los tipos, sin importar librerías. Solo los pasos, en orden, descritos con la precisión suficiente para que otra persona pueda seguirlos.

Es el plano antes del edificio. El guión antes de la película. La receta antes de cocinar.

— Ejemplo: calcular la media de una lista de números —

1. Recibir una lista de números
2. Contar cuántos números hay en la lista
3. Sumar todos los números
4. Dividir la suma entre el total
5. Devolver el resultado

— Ahora en Python —

def media(numeros):
    total = len(numeros)
    suma = sum(numeros)
    return suma / total
  1. Compara el pseudocódigo con el código Python. ¿Hay algún paso del pseudocódigo que no aparezca en el código? ¿Hay algo en el código que no estaba en el pseudocódigo? ¿Qué te dice eso sobre la relación entre los dos?
  2. Escribe el pseudocódigo para este problema: dado un listado de ventas diarias de un supermercado, identificar los tres días con ventas más altas y calcular qué porcentaje representan sobre el total. No escribas Python. Solo los pasos, en orden, en español.
  3. Dos personas resuelven el mismo problema con pseudocódigos distintos. Los dos son correctos. ¿Qué nos dice eso sobre la naturaleza del pseudocódigo? ¿Hay una única forma de descomponer un problema?
  4. ¿Qué ocurre si te saltas el pseudocódigo y le pides directamente a la IA que resuelva el problema? ¿Qué riesgo concreto introduces?
Respuesta orientativa
a

La correspondencia es casi exacta. El paso 1 del pseudocódigo (recibir la lista) se convierte en el parámetro numeros de la función. Los pasos 2 y 3 se convierten en las variables total y suma. El paso 4 es la división. El paso 5 es el return.

Lo que no estaba en el pseudocódigo es la sintaxis: la palabra def, los paréntesis, los dos puntos, la indentación. Esos son detalles del lenguaje, no de la lógica. El pseudocódigo captura la lógica; Python añade la forma.

Clave: si el pseudocódigo es correcto, traducirlo a Python es casi mecánico. Si el pseudocódigo es incorrecto o incompleto, el código resultante también lo será — independientemente de si lo escribe un humano o una IA.
b

Una posible solución:

1. Recibir la lista de ventas diarias
2. Calcular la suma total de todas las ventas
3. Ordenar la lista de mayor a menor
4. Tomar los tres primeros valores
5. Sumar esos tres valores
6. Dividir esa suma entre el total y multiplicar por 100
7. Devolver los tres días y el porcentaje

Este es solo un camino posible. Hay otros igualmente válidos: por ejemplo, calcular el porcentaje de cada día primero y luego ordenar por porcentaje. El resultado es el mismo.

c

El pseudocódigo no es único porque la lógica de resolución de un problema tampoco lo es. Hay múltiples caminos correctos para llegar al mismo resultado, igual que hay múltiples rutas para llegar al mismo destino.

Lo que sí es único es el resultado esperado. El pseudocódigo describe el camino, no el destino. Dos pseudocódigos distintos pueden ser igualmente correctos y producir resultados idénticos, o pueden diferir en eficiencia, claridad o robustez ante casos extremos.

Implicación práctica: cuando la IA genera código, elige uno de esos caminos posibles — no necesariamente el más adecuado para tus datos, tu contexto o tus restricciones. Sin haber pensado antes en el pseudocódigo, no tienes criterio para evaluar si el camino que eligió la IA es el que tú necesitas.
d

Si le pides directamente a la IA que resuelva el problema sin haber pensado en el pseudocódigo, el riesgo es doble.

Primero, tu prompt será vago porque no has descompuesto el problema en pasos. La IA interpretará los huecos de tu descripción — y esa interpretación puede no coincidir con lo que tú necesitabas.

Segundo, cuando la IA te devuelva el código, no tendrás ningún criterio para evaluarlo porque nunca pensaste en cómo debería resolverse el problema. Aceptarás o rechazarás el resultado por intuición, no por razonamiento.

El pseudocódigo como escudo: pensar en pseudocódigo antes de escribir un prompt no es un paso extra — es lo que convierte un prompt vago en una instrucción precisa, y lo que te da criterio para verificar que el código que recibes hace lo que necesitas.
Pseudocódigo y prompts: la misma cosa reflexión

Un prompt bien construido es un pseudocódigo disfrazado. La diferencia entre un prompt vago y un prompt preciso es exactamente la diferencia entre no haber pensado en el problema y haberlo descompuesto en pasos antes de escribir.

Abajo tienes el mismo problema formulado de tres formas distintas. Lee las tres versiones antes de responder las preguntas.

— El problema —

Tienes un fichero CSV con las ventas mensuales de una cadena de supermercados entre enero de 2022 y diciembre de 2024. Quieres predecir las ventas del primer trimestre de 2025.

— Versión A: prompt vago —

"Analiza mis ventas y predice el futuro."

— Versión B: prompt mejorado —

"Tengo un CSV con ventas mensuales de 2022 a 2024. Dame un modelo de predicción para el primer trimestre de 2025."

— Versión C: prompt desde pseudocódigo —

"Tengo un CSV con dos columnas: fecha (formato YYYY-MM) y ventas (euros), una fila por mes, de enero 2022 a diciembre 2024. Necesito: 1) cargar los datos y visualizar la serie para detectar tendencia y estacionalidad, 2) ajustar un modelo ARIMA eligiendo los parámetros automáticamente, 3) predecir las ventas de enero, febrero y marzo de 2025, 4) mostrar la predicción con un intervalo de confianza del 95%, 5) representar gráficamente la serie histórica y la predicción en el mismo plot."
  1. La Versión A deja muchas decisiones en manos de la IA. Enumera al menos cuatro decisiones concretas que la IA tendrá que tomar por su cuenta porque el prompt no las especifica. ¿Podrías verificar si esas decisiones son correctas sin haber pensado antes en el problema?
  2. La Versión B mejora la A pero sigue siendo incompleta. ¿Qué información relevante falta todavía? ¿Qué decisiones sigue tomando la IA por su cuenta?
  3. La Versión C es el pseudocódigo del Bloque 1 convertido en prompt. ¿Qué ha ganado respecto a las versiones anteriores? ¿Hay algo que todavía podría ser más preciso?
  4. Copia la Versión A y la Versión C en Claude o ChatGPT y compara los códigos que producen. ¿En qué se diferencian? ¿Cuál te da más criterio para verificar que el resultado es correcto?
Respuesta orientativa
a

Decisiones que la IA toma por su cuenta con la Versión A: qué columnas tiene el CSV y cómo se llaman, qué modelo de predicción usar (ARIMA, Prophet, XGBoost, Chronos...), qué horizonte temporal predecir, si visualizar o no la serie, si calcular intervalos de confianza, si detectar y tratar valores atípicos, si hay estacionalidad y cómo manejarla.

Sin haber pensado en el problema, no tienes criterio para evaluar ninguna de esas decisiones. Aceptas o rechazas el resultado por intuición, no por razonamiento. Es exactamente el error de nivel 2 que vimos en la Parte I con Chronos.

Un prompt vago no es un atajo: es una delegación de decisiones conceptuales a una herramienta que no conoce tu negocio, tus datos ni lo que está en juego.
b

La Versión B especifica el fichero y el horizonte temporal, pero sigue dejando sin respuesta preguntas importantes: ¿qué columnas tiene el CSV y qué formato tienen? ¿Qué modelo usar y con qué parámetros? ¿Hay que visualizar algo? ¿Se necesita un intervalo de confianza? ¿Cómo se presenta el resultado?

La IA elegirá por defecto el modelo que le parezca más apropiado para una serie mensual genérica — que puede no ser el adecuado para la estacionalidad específica de un supermercado.

c

La Versión C especifica la estructura del fichero, el modelo, el horizonte, la visualización y el formato del resultado. La IA ya no toma ninguna decisión conceptual por su cuenta: solo traduce instrucciones precisas a código.

Lo que todavía podría ser más preciso: el criterio para elegir los parámetros del ARIMA, cómo tratar los valores atípicos si los hay, y qué hacer si la serie no es estacionaria. Esos son detalles que requieren conocimiento estadístico — y son exactamente los que no puede sustituir la IA.

La conexión clave: la Versión C es posible porque alguien pensó antes en pseudocódigo. No es que sea un prompt más largo — es que detrás hay un problema descompuesto en pasos. La longitud es una consecuencia de la claridad, no un objetivo en sí mismo.
d

El código de la Versión A será genérico, probablemente corto, y lleno de suposiciones implícitas sobre la estructura de los datos. El de la Versión C será más largo, más específico, y cada parte corresponderá a un paso que tú mismo definiste.

La diferencia más importante no es la longitud del código sino tu capacidad de verificarlo. Con la Versión C puedes comprobar paso a paso si el código hace lo que pediste, porque tú definiste los pasos. Con la Versión A no tienes ese criterio — no sabes si el modelo que eligió la IA es el adecuado porque nunca pensaste en qué modelo necesitabas.

Resumen de la Parte IV: el pseudocódigo no es un ejercicio académico. Es la herramienta que convierte un prompt vago en una instrucción precisa, y que te da criterio para verificar que el código que recibes hace lo que necesitas. Sin él, la IA decide por ti. Con él, tú decides y la IA ejecuta.
Parte V

Tareas

Tareas para antes de la Clase 2 tareas

Tres tareas para completar antes de la próxima clase. No son opcionales: la Clase 2 parte de que las has hecho.

Tarea 1 Lectura — artículo del New York Times

Lee el artículo de Clive Thompson publicado en el New York Times: "Coding After Coders: The End of Computer Programming as We Know It". Está disponible en el mismo directorio que este documento.

↓ Abrir artículo (PDF)

Mientras lees, anota: ¿qué argumento hace Thompson sobre el futuro de la programación? ¿En qué coincide con lo que hemos discutido hoy? ¿En qué discrepa? Lo discutiremos al inicio de la Clase 2.

Tarea 2 Vídeo — introducción a los prompts

Ve este vídeo de 30 minutos sobre prompt engineering. Cubre los conceptos básicos que usaremos durante todo el curso: qué es un prompt, cómo estructurarlo, y las técnicas fundamentales de zero-shot y few-shot prompting.

▶ Ver vídeo — Prompt Engineering Guide (13 min)

Mientras lo ves, piensa en los tres prompts del Bloque 10 (Versiones A, B y C). ¿Qué técnicas del vídeo se aplicaron en la Versión C?

Tarea 3 Instalación — entorno de trabajo

Instala uv y crea el entorno virtual del curso siguiendo las instrucciones del documento adjunto. Es el gestor de entornos que usaremos durante todas las clases. Si tienes algún problema con la instalación, anótalo con detalle — lo resolveremos al inicio de la Clase 2.

↗ Guía de instalación de uv

Si usas Windows, Mac o Linux las instrucciones difieren ligeramente. El documento cubre los tres casos.

↗ Introducción JupyterLab