Skip to main content

Python en la era de la IA: un curso intensivo

17 Conceptos · Lee antes de escribir

Ya aprendiste a manejar un agente de codificación de IA en Agentic Coding Crash Course. Puede abrir una sesión, darle una instrucción a Claude Code o OpenCode y verlo editar archivos y ejecutar comandos. Así que aquí está la pregunta honesta que este curso pretende responder:

Si el agente escribe el Python, ¿por qué necesita aprender cualquier Python?

Porque alguien tiene que leerlo. El agente produce cientos de líneas de código funcional en segundos. Y "parecer trabajador" es la trampa. La IA optimiza lo plausible, no lo correcto. El código que silenciosamente devuelve un número incorrecto, elimina un registro o filtra su clave API se ve exactamente igual al código que funciona. La única persona que puede notar la diferencia es aquella que puede leer lo que escribió el agente y probar que hace lo que quiso decir.

Ese es todo el trabajo ahora. No escribir bucles desde una página en blanco. El agente hace eso. Su trabajo es la parte que todavía requiere un ser humano: decidir qué significa correcto y verificar que el código generado lo cumpla.

Dónde se encuentra este curso

Esta es la puerta de entrada a Programación en la era de la IA. Esa parte del libro es un curso profundo de 3 a 5 meses desarrollado en torno a un proyecto (SmartNotes). Este curso intensivo es la versión 80% de lectura en una sola: suficiente conocimiento sobre Python para comenzar a leer el código del agente hoy. Viene después de Agentic Coding y antes de Build AI Agents, Postgres for AI y Building a Digital FTE, los tres suponemos que puedes leer el Python que genera un agente. Para obtener el tratamiento completo de cualquier tema aquí, siga los enlaces de ese curso.

Una idea que organiza todo a continuación: en el viejo mundo, aprendías Python escribiéndolo. Aquí lo aprendes leyéndolo: prediciendo qué hace el código, ejecutándolo, investigando por qué, luego cambiándolo y finalmente construyendo el tuyo propio. Tenemos un nombre para ese bucle y es la columna vertebral de todo el curso.

Todo en este curso es algo que tú haces dentro de una sesión Claude Code, no solo lee sobre ello. Mantén una terminal abierta con claude ejecutándose y prueba cada idea a medida que la alcance.

Todo en este curso es algo que tú haces dentro de una sesión OpenCode, no solo lee sobre ello. Mantén una terminal abierta con opencode ejecutándose y prueba cada idea a medida que la alcance. Si está observando los costos, apunte a un modelo económico como deepseek-v4-flash para las ejecuciones de rutina (consulte el curso de Codificación agentic).


Configura su entorno (una vez)

Este curso tiene un pequeño complemento que se descarga una vez: la base del curso. No es estrictamente necesario para seguir leyendo, pero hace que todo se comporte como supone el curso. Incluye un breve archivo de reglas, AGENTS.md, que convierte a tu agente en el tutor disciplinado en el que se basa este curso: predice antes de revelar, da sugerencias en lugar de respuestas y nunca debilita silenciosamente una prueba solo para hacerla pasar. Su agente lee ese archivo automáticamente cada vez que se inicia, por lo que sus indicaciones aquí pueden ser breves. La base también contiene los iniciadores de proyectos de práctica y una clave de respuestas con la que puede comparar sus propios exámenes.

Descargar python-crash-course-base.zip

Descomprímalo, luego abre tu agente dentro de la carpeta:

cd python-crash-course
claude
cd python-crash-course
opencode

Observa que la base se envía aún no hay proyecto Python, a propósito. Construir su propio banco de trabajo a partir de la nada es la primera habilidad real y es lo siguiente que debe hacer, en Concepto 3. Por ahora, simplemente abre tu agente en la carpeta y confirme que cargó las reglas:

¿Qué reglas estás siguiendo para esta sesión?

Debe describir el método de lectura antes de escribir y el hábito de ejecutar pruebas para verificar. Listo cuando tu agente responde con esas reglas. (¿Prefieres comenzar desde una carpeta vacía? Eso también funciona; tú mismo establecerás la disciplina a medida que avanzas).


Parte 1: La nueva mentalidad

1. Lees el código; el agente lo escribe

En los cursos tradicionales Python, la habilidad que se entrena es producción: escribir la función, escribir el bucle, escribir la clase. La IA eliminó ese cuello de botella. La habilidad que importa ahora es dirección y verificación.

El trabajo anterior (ahora mayoritariamente automatizado)El nuevo trabajo (aún tuyo)
Escribe la implementación desde una página en blancoDescribe con precisión lo que quieres, en palabras que el agente pueda actuar.
Memorizar la sintaxisReconocer la sintaxis lo suficientemente bien como para leerla críticamente
Obtener el código para ejecutarDemuestre que el código es correcto, no sólo ejecutable

Esta es la regla 10-80-10 aplicada a la programación. Eres dueño del primer 10% (decidir qué construir y qué significa "correcto") y del último 10% (verificarlo). El agente posee el 80% del medio (generando el código). Leer con fluidez es lo que te permite conservar ambos extremos.

The 10-80-10 rule: you own the first 10% (decide what's correct) and the last 10% (verify); the agent owns the 80% in the middle (generate the code).

No necesitas memorizar nada.

Leer es mucho más fácil que escribir. No es necesario recordar, de la nada, que una lista utiliza corchetes. Solo necesita reconocer ["a", "b"] como una lista cuando la vea. Ése es el listón de todo este curso: reconocimiento, no recuerdo.

2. El método PRIMM-AI+

PRIMM-AI+ es la forma de aprender a leer código sin tener que mirar una página en blanco. Cada nueva pieza de Python pasa por cinco pasos, y el agente es su socio en cada uno de ellos:

pasocartaque hacesEl papel del agente
PredecirpagAntes de que se ejecuta algo, adivina qué hará el código.Permanece en silencio: esta es tu suposición
EjecutarREjecútelo y vea el resultado real.Ejecuta el código por ti.
InvestigaryoCompare su suposición con la realidad; pregunta por quéExplica línea por línea, bajo demanda.
ModificarmCambia una cosa, predice de nuevo, corre de nuevoHace la edición que describe
HacermEspecifique su propia versión desde cero; dejar que el agente lo construye; verificarGenera contra tus especificaciones

The PRIMM-AI+ loop: Predict, Run, and Investigate build reading fluency; Modify and Make direct the agent; the loop repeats. La IA+ es la parte que hace que esta sea la versión de la era de la IA de un antiguo método de enseñanza. Dos cosas se superponen al clásico PRIMM: el agente siempre está disponible como compañero de lectura ("explica la línea 3", "¿qué estropearía esto?"), y nada se acepta por fe. Predecir-Ejecutar-Investigar desarrolla tu fluidez de lectura; Modify-Make es donde comienzas a dirigir al agente. Al final, Make se siente tan natural como Predict ahora.

Donde caben las pruebas: en todas partes. El motor que impulsa Investigar, Modificar y Crear es la prueba: una breve verificación que precisa lo que significa "correcto", para que el equipo pueda verificar el trabajo del agente en lugar de que tú lo observe. Este no es un paso que se hace una vez al final. A partir de la siguiente función que lee, se realiza una pequeña prueba: primero como una única línea assert (Concepto 5), luego en objetos (Concepto 8) y reglas de validación (Concepto 11) y, finalmente, como el ciclo completo Test-Driven Generation donde tú escribe la prueba primero y el agente escribe el código para pasarla (Concepto 16). Trate cada fragmento de código que le entregue el agente como si no fuera de confianza hasta que una prueba que haya escrito indique lo contrario.

Predecir no es opcional

El instinto es saltar directamente a Ejecutar: basta con ver la respuesta. No. La brecha entre su predicción y el resultado real es donde ocurre el aprendizaje. Una predicción incorrecta te dice exactamente qué parte de tu modelo mental está rota, mucho mejor que una correcta. Predecir en voz alta, por escrito o al agente. Entonces corre.

3. Tu mesa de trabajo en cinco minutos

¿Llega frío? Consiga al agente primero

Este curso supone que ha realizado el Agentic Coding Crash Course, donde instala y aprende a manejar el agente. Si saltó directamente aquí y aún no tiene nada instalado, configura un agente de codificación antes de continuar. Esa única herramienta instalará todo lo demás por ti:

No es necesario que comprenda profundamente ninguna de estas herramientas. Instale un agente, ábralo en una carpeta y continúe. El resto de esta sección hace que el agente realice la configuración.

Necesita tres cosas: una forma de ejecutar Python, algunas herramientas de calidad y tu agente. Un instalador cubre los dos primeros: uv, un administrador de paquetes rápido que instala Python y administra su proyecto.

No los instale manualmente desde la memoria; ese es exactamente el tipo de configuración complicada en la que el agente es bueno. En la carpeta donde abriste tu agente, dale una instrucción:

Configura un nuevo proyecto Python aquí usando uv. Agrega pytest para pruebas, pyright para verificación de tipo y ruff para formateo. Crea un hello.py que imprima "listo". Luego ejecútelo y muéstreme el resultado.

El agente ejecutará los comandos uv, creará los archivos y ejecutará el script. Observas y apruebas cada paso. Ese es tu banco de trabajo. No memorizaste ni un solo comando.

No los instale manualmente desde la memoria; ese es exactamente el tipo de configuración complicada en la que el agente es bueno. En la carpeta donde abriste tu agente, dale una instrucción:

Configura un nuevo proyecto Python aquí usando uv. Agrega pytest para pruebas, pyright para verificación de tipo y ruff para formateo. Crea un hello.py que imprima "listo". Luego ejecútelo y muéstreme el resultado.

OpenCode ejecutará los comandos uv, creará los archivos y ejecutará el script. Observas y apruebas cada paso. Ese es tu banco de trabajo. No memorizaste ni un solo comando.

Cómo se ve eso realmente

No se mira en silencio. El agente narra cada paso y pregunta antes de ejecutar algo. Una sesión real se parece más o menos a esto (se muestra Claude Code; OpenCode es casi idéntico):

> Set up a new Python project here using uv. Add pytest, pyright, ruff.
Create a hello.py that prints "ready", run it, and show the output.

● I'll initialize the project with uv.
$ uv init . ← the agent proposes a command
Allow? (y/n) y ← you approve
Initialized project

● $ uv add --dev pytest pyright ruff
Allow? (y/n) y
+ pytest + pyright + ruff

● Created hello.py:
print("ready")

● $ uv run hello.py ← this is how a Python file gets run
ready ← the output prints right here

Done. Your workbench is ready.

Tres cosas a tener en cuenta, porque son el bucle físico que repetirás durante todo el curso:

  • El código se encuentra en un archivo (hello.py), no en la ventana de chat.
  • Ejecutas un archivo con uv run hello.py: ese comando ejecuta todos los scripts y ejemplos de este curso.
  • El agente pide permiso antes de cada comando y luego imprime el resultado debajo. Lo apruebas, lees el resultado.

Entonces, cada vez que un ejemplo a continuación dice "ejecutarlo", tiene dos opciones sencillas: pegar el código en un archivo y decirle al agente "ejecuta este archivo y muéstreme el resultado" o simplemente pega el fragmento en el chat y di "ejecuta esto y muéstreme lo que imprime". De cualquier manera, nunca escribe Python a mano.

Si la configuración falla, tú no la depura, el agente lo hace

Si algún paso arroja un error rojo, no es necesario que lo comprendas. Copia el texto rojo, péguelo nuevamente y diga: "esto falló. Lee el error y corríjalo". Si el agente informa que uv no está instalado, pídele que instale uv primero. Despegarse es el trabajo del agente; Darte cuenta de que estás estancado es tuyo.

Esto es lo que hace cada herramienta, en una línea. Verás los cuatro mencionados constantemente a partir de aquí:

Herramienta¿Qué hace por ti?
uvInstala Python y los paquetes de su proyecto, rápidamente
pytestEjecuta sus pruebas e informa cuáles pasaron y cuáles fallaron.
PyrightLee las etiquetas de tipo en el código y marca las discrepancias antes de ejecutarlo.
RuffComprueba el estilo y el formato: un corrector ortográfico para el código
Por qué esto es importante para la lectura

Pyright y Ruff son máquinas de lectura. Cuando el agente genera código, estas herramientas lo leen por tú y detectan toda una clase de errores al instante: un tipo incorrecto, una variable no utilizada, un nombre escrito con error. Son su primera línea de verificación, incluso antes de que tú mismo leas una línea. (Tutorial de instalación completo: Programación en la era de la IA, Fase 1: The Workbench.)

Mira cómo tus máquinas de lectura captan algo

Estas herramientas no son abstractas. Pídele al agente que escriba una pequeña función y luego la llame con el tipo de valor incorrecto:

def total_with_tax(price: float, tax_rate: float) -> float:
return price + (price * tax_rate)

total_with_tax("100", 0.15) # oops — "100" is text, not a number

Ejecuta pyright en él y obtendrá esto antes de que se ejecute el código:

error: Argument of type "Literal['100']" cannot be assigned to
parameter "price" of type "float" (reportArgumentType)

Pyright leyó las sugerencias de tipo, vio que se pasó texto donde se prometió un float y detectó la discrepancia al instante. Ruff detecta una clase diferente de desliz: restos de desorden que el agente a veces deja atrás:

F401  `os` imported but unused

No memorizas estos mensajes. Los lees de la misma manera que lees el subrayado de un corrector ortográfico: algo aquí no encaja y apunta a la línea exacta. Cuando el agente genera cien líneas, estas dos herramientas las leen todas en menos de un segundo, que es exactamente la razón por la que se ejecutan antes de que tú comience a leerlas tú mismo.


Parte 2: Las formas que verás en todas partes

Estas son las formas centrales que constituyen quizás el 70% de todo el Python que jamás leerás. Desplácese por cada uno con Predecir → Ejecutar → Investigar: léalo, adivine el resultado y luego ejecútelo en su sesión para comprobarlo.

4. Valores, variables y los cuatro tipos

Una variable es un cuadro etiquetado que contiene un valor. El signo = significa "poner el valor de la derecha en el cuadro de la izquierda": no es "igual" en el sentido matemático. Cada valor tiene un tipo y, por ahora, solo hay cuatro que debes reconocer. Escribimos el tipo justo después del nombre, como name: type, para que tanto tú como el agente puedan ver de un vistazo lo que debe contener cada casilla:

name: str = "Ayesha"        # str   — text, always in quotes
age: int = 30 # int — a whole number
price: float = 19.99 # float — a number with a decimal point
is_active: bool = True # bool — only ever True or False

Las piezas : str, : int, : float, : bool son sugerencias de tipo. Son opcionales en Python, pero a lo largo de este curso siempre los incluimos: en parte porque hacen que el código sea más fácil de leer y en parte porque, como verá en el Concepto 10, son la forma en que le dice al agente exactamente qué compilar. Por ahora, lee name: str en inglés sencillo: "el cuadro name contiene texto".

Predecir: ¿Qué crees que se imprime?

age: int = 30
age = age + 1
print(age)

Ejecútelo. El resultado es 31. Investigue: la línea age = age + 1 parece imposible si lee = como "igual": 30 no puede ser igual a 31. Pero = significa asignar: tome el valor actual de age (30), agrega 1 y coloque el resultado (31) nuevamente en el cuadro. El lado derecho se ejecuta primero y luego se actualiza el cuadro. (Observa que solo escribimos la sugerencia de tipo : int la primera vez que apareció age; una vez que el cuadro tiene un tipo, no lo repites en cada reasignación). Esta idea hace tropezar a casi todos al principio, y es por eso que la predijiste primero.

movimiento de lectura

Cuando vea x = something, léalo de derecha a izquierda: "calcule something y luego guárdelo en x". El nombre de la izquierda es sólo una etiqueta.

5. Funciones y sus firmas

Una función es un bloque de código reutilizable con un nombre. Le das entradas (llamadas argumentos), y te devuelve una salida. La primera línea, la firma, es la línea más importante que aprenderá a leer, porque es un contrato:

def total_with_tax(price: float, tax_rate: float) -> float:
return price + (price * tax_rate)

Lee la firma pieza por pieza:

  • def: "Estoy definiendo una función".
  • total_with_tax: su nombre.
  • (price: float, tax_rate: float): se necesitan dos entradas, ambas decimales. La parte : float es una pista de tipo (más sobre esto en el Concepto 10).
  • -> float: devuelve un decimal.

De una vez: "dame un precio y un tipo impositivo, ambos decimales, y te devolveré un decimal." Puedes entender lo que promete una función sin leer una sola línea de su cuerpo. Es por eso que las firmas son tan importantes cuando se verifica el código IA. El cuerpo puede estar equivocado; la firma te dice lo que se suponía que debía hacer.

Predecir y luego ejecutar:

def total_with_tax(price: float, tax_rate: float) -> float:
return price + (price * tax_rate)

print(total_with_tax(100.0, 0.15))

Salida: 115.0. Si predijo 115.0, ya puede leer una función.

Fijarlo con una prueba

Una función es lo primero que puedes probar que es correcta, porque tiene un contrato claro: dadas estas entradas, debe devolver esa salida. Puedes bloquear eso con assert: un reclamo de una línea que no hace nada cuando es verdadero y falla ruidosamente en el momento en que es falso:

assert total_with_tax(100.0, 0.15) == 115.0   # "I claim this must equal 115.0"
assert total_with_tax(0.0, 0.15) == 0.0 # a free item costs nothing

Ejecuta esas dos líneas y verá nada. El silencio significa cada reclamo sostenido. Cambia el 115.0 a 999.0 y fallará instantáneamente. Esa es la idea detrás de las pruebas: escribes lo que significa correcto, una vez, y el equipo lo vuelve a verificar cada vez. Estas dos líneas ya son una pequeña especificación. Agárrate a ellos. En el Concepto 16, entregará estas afirmaciones exactas al agente y le pedirá que escriba la función para satisfacerlas. (Esto no es casualidad: la misma función fiscal reaparece allí como ciclo completo TDG).

6. Colecciones: agrupar datos

Los valores únicos son raros en el código real. La mayoría de los datos vienen en grupos y hay cuatro contenedores que verás una y otra vez:

notes: list[str] = ["buy milk", "call Sara", "finish report"]   # list  — ordered, can change
note: dict[str, str | bool] = {"title": "Meeting", "done": False} # dict — labeled pairs (key: value)
tags: set[str] = {"work", "urgent"} # set — unique items, no duplicates
point: tuple[int, int] = (3, 5) # tuple — ordered, cannot change

Las sugerencias describen lo que hay dentro del contenedor: list[str] es "una lista de texto", dict[str, str | bool] es "un dictado cuyas claves son texto y cuyos valores son texto o verdadero/falso" (| significa "o"), set[str] es "un conjunto de texto" y tuple[int, int] es "un par de números enteros". No es necesario escribirlos de memoria. Necesitas leerlos.

Los dos que conocerá más son lista (una secuencia que puede agregar y reordenar) y dict (un conjunto de valores etiquetados: la columna vertebral de casi todos los datos que pasa un agente de IA, porque se asigna directamente a JSON).

Predecir y luego ejecutar:

note: dict[str, str | bool] = {"title": "Meeting", "done": False}
print(note["title"])
note["done"] = True
print(note)

Salida:

Meeting
{'title': 'Meeting', 'done': True}

Investigar: note["title"] busca en el dict y saca el valor etiquetado como "title". La segunda línea cambia el valor etiquetado como "done". Un dict es la forma en que el agente le entregará una nota, un usuario, una respuesta API: cualquier cosa con campos con nombre.

7. Controlar el flujo y las comprensiones.

El código toma decisiones con if y repite con for. La sangría (los espacios al comienzo de una línea) es la forma en que Python sabe qué pertenece dentro de if o for. No es decoración, es estructura.

prices: list[int] = [10, 250, 50, 400]

for price in prices: # do this once for each price in the list
if price > 100: # decision
print(f"{price} is expensive")
else:
print(f"{price} is fine")

Predice qué líneas se imprimen "caras" antes de ejecutarlas. (Respuesta: 250 y 400.)

Dos de esas líneas usan una f-string: texto con un f al frente, donde cualquier cosa dentro de {...} se reemplaza por su valor. Entonces f"{price} is expensive" coloca el actual price en la oración. Verás cuerdas f constantemente; simplemente reconozca que {name} significa "ponga el texto de este valor aquí".

Cuando una decisión tiene más de dos resultados, elif (abreviatura de "si no") los encadena. Python comprueba cada rama de arriba a abajo y ejecuta la primera que es verdadera:

def grade_for(score: int) -> str:
if score >= 90:
return "A"
elif score >= 70:
return "B"
elif score >= 50:
return "C"
else:
return "F"

Predecir grade_for(72) y luego ejecutar. Es "B": 72 >= 90 es falso, por lo que pasa a la siguiente rama, 72 >= 70 es verdadero y se detiene allí. Lee una cadena if/elif/else como "verifica estos en orden; tome la primera coincidencia". También verá condiciones combinadas con and y or (if score >= 70 and attended: significa que ambos deben ser verdaderos), que es todo lo que necesita para leer decisiones de "criterios múltiples".

Una vez que pueda leer un bucle for, podrá leer la frase más común en Python: la comprensión. Es solo un bucle for doblado en una línea para crear una nueva lista:

prices: list[int] = [10, 250, 50, 400]

# The long way:
expensive: list[int] = []
for price in prices:
if price > 100:
expensive.append(price)

# The comprehension — exactly the same result:
expensive = [price for price in prices if price > 100]

El .append(price) en la versión larga añade price al final de la lista; esa forma thing.action() es la llamada al método que encontrará en el Concepto 8. Lee la comprensión de izquierda a derecha: "dame price, para cada price en prices, si price > 100". Ambos producen [250, 400]. Verá comprensiones en todas partes del código de IA porque la limpieza y remodelación de datos es la mayor parte del trabajo. Siéntase cómodo reconociendo esta forma y podrá leer una gran cantidad de Python real.

Usa al agente como compañero de lectura

Pega cualquier línea que no comprenda en su sesión: "Explique esta línea como si nunca hubiera codificado: [n['text'] for n in notes if n['done']]." Este es el paso Investigar de PRIMM-AI+, bajo demanda. Úselo constantemente. Es más rápido que cualquier referencia.

8. Clases y objetos: leer un plano

Hasta ahora tus datos han estado sueltos: un note era un dict, un price era un flotante. Una clase le permite agrupar datos relacionados y las acciones que pertenecen a ellos en una forma con nombre. Piense en una clase como un plano y en un objeto (también llamado instancia) como algo construido a partir de ese plano: un plano Note, muchas notas reales creadas a partir de él.

Aquí hay una clase que modela una sola nota:

class Note:
def __init__(self, title: str, body: str) -> None:
self.title = title # an attribute — data this note carries
self.body = body
self.done = False

def mark_done(self) -> None: # a method — an action this note can perform
self.done = True

Léelo en pedazos:

  • class Note:, define el plano, denominado Note.
  • __init__: el método de configuración. Se ejecuta una vez, automáticamente, cuando crea una nueva nota y almacena los datos iniciales. (-> None significa que no devuelve nada; simplemente configura el objeto).
  • self: este objeto en particular. Dentro del plano, self.title significa "título de esta nota". Cada método toma primero self para saber en qué objeto está trabajando.
  • self.title, self.body, self.doneatributos: los datos que lleva cada nota.
  • mark_done, un método: una función que vive dentro de la clase y actúa sobre el objeto.

Ahora construye uno y úsalo. Predice el resultado antes de ejecutarlo:

n: Note = Note(title="Groceries", body="milk, eggs")
print(n.done)
n.mark_done()
print(n.done)

Salida:

False
True

Investigar: Note(title="Groceries", body="milk, eggs") ejecuta __init__ y devuelve un objeto terminado, almacenado en n. n.done lee un atributo; n.mark_done() llama a un método que lo cambia. El punto (.) siempre significa lo mismo: "busca en este objeto la cosa que lleva su nombre".

Ese patrón (object.attribute para leer datos y object.method() para pedirle al objeto que haz algo) desbloquea el Python más real. Casi todo lo que leerá en el código del agente son objetos: un modelo Pydantic es una clase, un agente es un objeto, una conexión de base de datos es un objeto. Cuando vea agent.run(task) o db.save(note), estará leyendo "solicite a este objeto que ejecute uno de sus métodos". (El modelo de objeto completo es Programación en la era de la IA, Fase 5.)

Fijarlo con una prueba

Verificas un objeto exactamente de la misma manera que verificaste la función en el Concepto 5: afirma cuál debe ser su estado antes y después de que se ejecuta un método:

n: Note = Note(title="Groceries", body="milk, eggs")
assert n.done is False # a fresh note starts unfinished
n.mark_done()
assert n.done is True # ...and is finished after mark_done()

Mismo movimiento, nuevo objetivo: un método es solo una función adjunta a un objeto, por lo que el mismo assert de una línea demuestra su comportamiento. Cuando el agente escribe una clase para ti, así es como verifica que haz lo que tú quería decir.

Aún no escribes clases, las lees

Como ocurre con todo en este curso, el objetivo aquí es el reconocimiento. Cuando el agente genera una clase, tú quiere poder señalarla y decir "ese es el método de configuración, esos son sus atributos, ese es un método que cambia su estado". Eso es suficiente para verificar que hace lo que pediste.

9. Más formas que encontrará en el código generado: while, corte, try/except y input()

Rara vez escribirá estos cuatro, pero el agente los usa constantemente, por lo que debe reconocerlos cuando lee y verifica su salida. Un rápido Predecir → Ejecutar → Investigar en cada uno es suficiente.

while: repita hasta que cambia una condición. Cuando un bucle for se ejecuta una vez por elemento de una colección, un bucle while continúa mientras su condición siga siendo verdadera:

count: int = 3
while count > 0: # keep looping while this is true
print(count)
count = count - 1
print("done")

Predecir y luego ejecutar. Salida: 3, 2, 1, done. Léelo como "sigue haciendo esto mientras count > 0". Un peligro que vale la pena reconocer en el código generado: si la condición nunca se vuelve falsa, el bucle se ejecuta para siempre, así que cuando veas un while, mira lo que finalmente hace que se detenga.

Cortar: toma una parte de una lista o cadena. Dos puntos dentro de los corchetes significan "un rango de posiciones":

letters: list[str] = ["a", "b", "c", "d", "e"]
print(letters[1:3]) # from position 1 up to (not including) 3
print(letters[:2]) # the first two
print(letters[-1]) # the last one

Predecir y luego ejecutar. Salida: ['b', 'c'], ['a', 'b'], e. El conteo comienza en 0; [1:3] es "desde 1 hasta 3, pero sin incluir"; -1 significa "el último". La misma sintaxis funciona con texto: "hello"[:3] es "hel".

try / except: intenta algo que podría fallar. Algunas operaciones pueden fallar: dividir por cero, leer un archivo faltante, agotar el tiempo de espera de una llamada de red. try/except ejecuta el código riesgoso y detecta el error en lugar de fallar:

def safe_divide(a: float, b: float) -> float:
try:
return a / b
except ZeroDivisionError: # if dividing by zero is attempted...
return 0.0 # ...do this instead of crashing

Predecir safe_divide(10.0, 2.0) y safe_divide(10.0, 0.0), luego ejecutar. Salidas: 5.0 y 0.0. Léalo como "prueba esto; si falla de esta manera específica, hágalo así". Verá try/except incluido todo lo que pueda fallar en el código del agente.

input(): pausa y lee lo que escriba el usuario. Los scripts interactivos y las herramientas de línea de comandos utilizan input() para hacerle una pregunta a la persona y esperar una respuesta:

name: str = input("What's your name? ")   # waits here until the user types and presses Enter
print(f"Hello, {name}!")

Lo único que hay que reconocer, y el único lugar en el que el código generado suele pasar desapercibido, es que input() siempre devuelve texto, incluso cuando el usuario escribe un número. Para hacer cálculos con él, el código debe convertirlo primero:

age_text: str = input("Your age? ")   # "30" comes back as text, not a number
age: int = int(age_text) # int(...) converts text to a whole number
print(f"Next year you'll be {age + 1}")

Si alguna vez ve que input() ingresa directamente a la aritmética sin un int(...) o float(...) a su alrededor, es un error a señalar: el programa fallará o pegará el texto en lugar de agregarlo.

Fijarlo con una prueba

El caso de error es exactamente el tipo de cosas que vale la pena señalar: afirmar que la entrada peligrosa se maneja, no se bloquea:

def test_safe_divide() -> None:
assert safe_divide(10.0, 2.0) == 5.0
assert safe_divide(10.0, 0.0) == 0.0 # handled, not a crash
Por qué son importantes para la verificación

Cada uno es un lugar común para que el código generado salga sutilmente mal: un while que nunca termina, una porción que está desviada por uno ([1:3] le da dos elementos, no tres), un except que silenciosamente se traga un error que necesitaba conocer, o un input() cuyo texto nunca se convierte a un número antes de las matemáticas. Reconocer la forma es lo que te permite detenerte y mirar más de cerca exactamente esos puntos.


Parte 3: Los conceptos de poder de la era de la IA

Estos conceptos son los que separan el "hola mundo" Python del Python que realmente verá en el código de agente y ML. La mayoría de ellos no los escribirás desde cero todavía; el agente hace eso, y su objetivo es puro reconocimiento: cuando aparece uno, sabe para qué sirve y aproximadamente para qué hace. La única excepción es la primera, sugerencias de tipo (Concepto 10): aquellas que aprendes a escribir, porque son la forma en que le dices al agente exactamente qué construir. (Varios provienen directamente de lo que los ingenieros de producción de IA usan a diario).

Zona de sólo lectura: que no cunda el pánico

El ritmo se acelera aquí, a propósito. Hace dos páginas estabas leyendo age = age + 1; ahora verá generadores, validadores y async. Está bien. No se espera que escribas nada de esto. Tu única tarea para los Conceptos 11 a 15 es reconocer cada forma y decir en inglés sencillo para qué sirve. Si un bloque parece denso, lee el resumen de una línea "léelo como..." y continúa. Nadie los memoriza; aprendes a detectarlos.

10. Escribe sugerencias: las etiquetas que guían al agente

Ya conociste a uno en el Concepto 5: price: float. Una sugerencia de tipo es una etiqueta que dice qué tipo de datos espera una variable o función. Python no los requiere, pero en la era de la IA son la herramienta más poderosa, por una razón:

Las sugerencias de tipo son instrucciones para el agente. Cuando escribe una firma como esta antes de pedirle al agente que la complete:

def summarize_notes(notes: list[dict], max_words: int) -> str:
... # the agent writes this part
  • le ha dicho, de manera precisa y sin ambigüedades, que la entrada es una lista de diccionarios, que hay un límite de palabras que es un número entero y que la salida es una sola cadena. El agente ahora genera lo correcto con mucha más frecuencia, porque eliminó las conjeturas. Y Pyright lee estas etiquetas y señala cualquier discrepancia antes de que se ejecute el código.

En términos de TDG (tratado completamente en Programación en la era de la IA), escribir los tipos es parte de escribir la especificación. El primer 10% es suyo.

La anatomía de una buena solicitud de "generar esto"

Dado que los tipos son instrucciones, las solicitudes de código más potentes le entregan al agente tres cosas y le piden una cuarta:

  1. La firma, con tipos: summarize_notes(notes: list[dict], max_words: int) -> str. Esto fija las entradas y la salida para que no haya conjeturas.
  2. Uno o dos ejemplos de entrada → salida. (Estos también sirven como pruebas).
  3. Cualquier restricción: "debe manejar una lista vacía", "no llamar a la red", "mantenerla por debajo de 20 líneas".
  4. Pídele que verifique: "luego ejecuta pytest y pyright y muéstrame el resultado".

Una solicitud vaga ("escribe algo para resumir las notas") obtiene un código vago. Una firma mecanografiada más un ejemplo obtiene un código que realmente puede verificar. Y cuando el resultado sea incorrecto, no presione simplemente reintentar: pega el resultado fallido y di lo que está mal: "se bloquea en una lista vacía. Ocúpese de eso". Una corrección informada supera a diez repeticiones ciegas.

11. Clases de datos y Pydantic: datos estructurados y validados

Un dictado sin formato ({"learning_rate": 0.001}) es flexible pero peligroso: una clave mal escrita o un tipo incorrecto pasa silenciosamente y corrompe todo lo posterior. Dos herramientas solucionan este problema.

Una instalación primero

Pydantic no está integrado en Python, por lo que los ejemplos siguientes necesitan que se agrega a su proyecto una vez: dile a tu agente "agrega pydantic a este proyecto" (ejecuta uv add pydantic). dataclass está integrado y no necesita nada.

Una clase de datos le da a tus datos una forma definida. Este es el mismo Note del Concepto 8. Pero observa que no hay __init__: la línea @dataclass escribe el método de configuración para tú, por lo que solo enumera los atributos y sus tipos.

from dataclasses import dataclass

@dataclass
class Note:
title: str
body: str
done: bool = False # default value

Pydantic va más allá: valida los datos en tiempo de ejecución y rechaza todo lo que no encaja:

from pydantic import BaseModel, Field

class ModelConfig(BaseModel):
learning_rate: float = Field(gt=0.0, lt=1.0) # must be between 0 and 1
batch_size: int = Field(gt=0) # must be positive

Si intenta construir un ModelConfig con learning_rate=-0.05, Pydantic genera un error claro inmediatamente en lugar de permitir que un valor roto envenene una ejecución de entrenamiento horas después. Esta es la razón por la que Pydantic está en todas partes en el código del agente: también genera automáticamente los esquemas JSON que los LLM utilizan para llamar a herramientas. Lo volverás a encontrar en el momento en que comiences a crear agentes.

Fijarlo con una prueba

Un modelo Pydantic es esencialmente una prueba que se ejecuta cada vez que lo hace su programa. Pero aun así debes fijar el comportamiento que te interesa, incluidos los casos de error. Hasta ahora has afirmado que algo es verdadero; aquí tú afirma que la entrada incorrecta debe ser rechazada, usando pytest.raises:

import pytest
from pydantic import ValidationError

def test_rejects_negative_learning_rate() -> None:
with pytest.raises(ValidationError): # the block below MUST raise this error
ModelConfig(learning_rate=-0.05, batch_size=32)

Esta prueba pasa solo si se rechaza la configuración incorrecta. Probar las fallas es tan importante como probar los éxitos: el agente generará felizmente una validación que parece estricta pero silenciosamente deja pasar datos incorrectos, y una prueba "debe generar" es la forma de detectar eso.

La línea @dataclass es un decorador.

Ese símbolo @ en la línea encima de una función o clase es un decorador: una etiqueta que agrega comportamiento a lo que le sigue, sin que tú mismo escribe ese comportamiento. @dataclass le da automáticamente a la clase un constructor y una impresión legible. No es necesario que escribas decoradores todavía; simplemente reconozca que @something significa "envolver lo siguiente con poderes adicionales".

12. Generadores y yield: streaming sin quedarse sin memoria

Cuando el código necesita procesar un millón de registros, cargarlos todos en una lista a la vez puede agotar la memoria de tu equipo. Un generador resuelve esto devolviendo elementos uno a la vez, según demanda. La señal a buscar es la palabra clave yield en lugar de return:

from collections.abc import Iterator

def stream_notes(lines: list[str]) -> Iterator[str]:
for line in lines:
yield line.strip().lower() # hand back one item, then pause

El tipo de devolución Iterator[str] es el signo revelador de un generador: no promete un list[str] (una pila terminada). Promete un iterador, una secuencia que extraes de un elemento a la vez.

Una función normal con return genera el resultado completo y lo entrega de una sola vez. Un generador con yield se detiene después de cada elemento y solo realiza el siguiente trabajo cuando se le solicita. La recompensa es real: transmitir un gran conjunto de datos a través de un generador en lugar de cargarlo en una lista puede reducir drásticamente el pico de memoria, porque nunca se puede almacenar todo a la vez. Cuando vea yield, léalo como: "esto produce un flujo, no una pila".

13. with: abre y cierra cosas de forma segura

Archivos, conexiones de bases de datos, sesiones de red (cualquier cosa que deba abrirse y luego cerrarse de manera confiable, incluso si algo falla en el medio) utiliza la declaración with:

with open("notes.txt") as file:
contents: str = file.read()
# the file is automatically closed here, even if an error happened above

Se garantiza que lo que se administra (aquí, el archivo) se limpiará cuando finalice el bloque sangrado. En el código IA verá with alrededor del estado de la GPU, el modo de evaluación del modelo y los temporizadores. Cuando vea with, léalo como: "prepara algo, úsalo dentro de este bloque y destrúyelo de forma segura pase lo que pase".

14. async / await: muchas cosas a la vez

Cuando un agente realiza 20 llamadas API, hacerlas una tras otra significa esperar 20 veces. El código asincrónico permite que el programa active todas las solicitudes y maneje las respuestas a medida que llegan: la diferencia entre estar en 20 colas una por una y unirse a las 20 a la vez. Las señales son las palabras clave async y await:

async def query_llm(prompt: str) -> str:
response = await call_the_api(prompt) # pause here, let other work proceed
return response

A modo de ilustración: si 20 llamadas API toman aproximadamente 0,1 segundos cada una, ejecutarlas una tras otra toma aproximadamente 2 segundos, mientras que ejecutarlas simultáneamente con async puede finalizar aproximadamente en el tiempo de la llamada única más lenta, porque el total está limitado por la llamada más lenta, no por la suma. No es necesario escribir código asíncrono todavía. Simplemente reconozca: async/await significa "este código está diseñado para hacer muchas cosas lentas al mismo tiempo". Dependerá en gran medida de él cuando crea agentes.

15. Métodos Dunder: por qué funciona model(x)

Lo más extraño que leerás es un método con guiones bajos dobles en cada lado, como __init__ o __call__. Estos reciben el sobrenombre de "dunders" (doble guión bajo), y ya conoces uno: el método de configuración __init__ de Concept 8 es un tonto. Son métodos especiales que permiten que sus propios objetos se comporten como si estuvieran integrados.

class Pipeline:
def __init__(self, factor: float) -> None: # runs when you create the object
self.factor = factor

def __call__(self, x: float) -> float: # runs when you "call" the object like a function
return x * self.factor

pipeline = Pipeline(2.5)
print(pipeline(10.0)) # prints 25.0 — the object is called like a function

__init__ configura un nuevo objeto; __call__ es lo que hace que pipeline(10.0) funcione como si el objeto fuera una función. Esta es exactamente la razón por la que, en PyTorch y bibliotecas similares, se escribe model(x) y no model.forward(x): el marco define __call__ para realizar una configuración importante antes de ejecutar. Cuando vea errores, léalos como: "a este objeto se le está enseñando a actuar como un objeto nativo Python".

Acabas de aprender a leer el código IA

Detente y observa lo que pasó. Todavía no puedes escribir un generador o una función asíncrona desde una página en blanco. Y no es necesario. Pero ahora puede abrir un archivo que el agente generó y reconocer: "esa es una clase con sus atributos y métodos, esa es una sugerencia de tipo, ese es un modelo Pydantic que define un esquema de herramienta, ese es un generador de transmisión de datos, ese bloque with administra un recurso, esos dunders crean un conjunto de datos personalizado". Ese reconocimiento es la habilidad de verificación de la que depende todo el libro.


Parte 4: El bucle TDG, de extremo a extremo

Ha realizado Predecir-Ejecutar-Investigar en las Partes 2 y 3. Ahora las dos últimas letras de PRIMM-AI+, Modificar y Crear, que juntas son el ciclo Test-Driven Generation (TDG): el método que define la programación en la era de la IA.

16. Un ciclo completo, en tu herramienta

TDG invierte el orden anterior. En lugar de escribir código → tal vez probarlo, vaya: escribe una prueba fallida que defina "correcto" → deje que el agente genere código → ejecuta la prueba para verificar. La prueba no es una idea de último momento; es la especificación. Y debe venir de ti, porque si deja que el agente escribe tanto el código como la prueba, está comparando el trabajo de la IA con sus propias expectativas: no hay señal independiente en absoluto.

Aquí está el ciclo sobre la función tributaria del Concepto 5. Síguelo en tu sesión. The Test-Driven Generation loop: you write a failing test, the agent generates the code, you run the tests and verify; if a test is red you refine and repeat, if green you ship.

Paso 1: escribe el requisito como pruebas fallidas. Crea test_tax.py:

from tax import total_with_tax

def test_basic() -> None:
assert total_with_tax(100.0, 0.15) == 115.0

def test_zero_price() -> None:
assert total_with_tax(0.0, 0.15) == 0.0

Has visto estas afirmaciones exactas antes. Son las dos líneas que escribiste en el Concepto 5, ahora movidas a un archivo test_*.py para que pytest pueda ejecutarlas automáticamente. assert X == Y significa "Estoy declarando que X debe ser igual a Y; fallará estrepitosamente si no es así". Estas dos líneas definen lo que significa correcto antes de que exista cualquier código. Ejecuta pytest ahora y falla: todavía no hay ningún tax.py. Ese fallo es el punto. Tienes una definición precisa y ejecutable de hecho.

Lo único nuevo aquí es el orden: en los Conceptos 5, 8 y 11 escribiste la prueba para el código que ya existía. En verdadero TDG, tú escribe la prueba fallida primero y luego hace que el agente genere el código para aprobarla. La prueba deja de ser una verificación que se ejecuta después y se convierte en la especificación con la que construye el agente.

Paso 2: El agente genera la implementación. Ahora dale a tu herramienta las instrucciones:

Lee test_tax.py. Crea tax.py con una función total_with_tax(price: float, tax_rate: float) -> float que haga pasar ambas pruebas. Luego ejecuta pytest y muéstrame el resultado.

Claude Code lee sus pruebas, escribe tax.py y ejecuta pytest. Debido a que escribió las pruebas, tiene una verificación independiente de lo que produjo.

Lee test_tax.py. Crea tax.py con una función total_with_tax(price: float, tax_rate: float) -> float que haga pasar ambas pruebas. Luego ejecuta pytest y muéstrame el resultado.

OpenCode lee sus pruebas, escribe tax.py y ejecuta pytest. Debido a que escribió las pruebas, tiene una verificación independiente de lo que produjo.

Paso 3: Verifica e itere. Lee el resultado pytest. Dos marcas de verificación verdes (2 passed) significan que el código cumple con las especificaciones que tú definiste. Si está rojo, lees la falla (siguiente concepto) y luego refinas. No simplemente vuelves a incitar ciegamente y tener esperanza. Y observa una cosa de cerca: si el agente falla la prueba editando la prueba en lugar del código, deténgalo. La prueba es tu especificación; volverlo verde debilitándolo solo oculta el error.

Ese es el bucle completo y se asigna claramente a PRIMM-AI+ y la regla 10-80-10:

Paso TDGquien lideraPRIMM-AI+
Requisito de escritura + pruebas fallidas (el primer 10%)hacer
Generar la implementaciónAgente (el 80%)
Ejecutar pruebas, verificar, iterar (el último 10%)Investigar / Modificar
Agrega los casos extremos que se le ocurran

El agente es bueno sugiriendo pruebas que tú omitió, pregúntele: "¿qué casos extremos debo probar para un cálculo de impuestos?". Pero la decisión sobre qué casos definen "correcto" sigue siendo suya. ¿Precios negativos? ¿Impuesto cero? ¿Números muy grandes? Cada uno que agrega es una especificación más nítida.

Usa este bucle en todo: es el valor predeterminado, no el final

TDG no es una ceremonia reservada a grandes funciones. Ejecútelo en cada unidad que produzca el agente y que tenga un contrato verificable: cada función, cada método, cada regla de validación. Los assert de una línea de los conceptos 5, 8 y 11 fueron la semilla; una carpeta tests/ en crecimiento y llena de ellos es lo que le permite seguir confiando en un proyecto a medida que el agente lo cambia. Una regla práctica: si no puedes escribir una prueba para algo, todavía no entiendes lo que significa "correcto" para ello. Y el agente tampoco. Escribir la prueba es la forma de averiguarlo. A medida que tus proyectos crecen, esto también es lo que te protege de regresiones: el agente arregla una cosa y silenciosamente rompe otra. Su conjunto de pruebas es la alarma que lo detecta.

Leer un rastreo (cuando se rompe)

Cuando Python falla, imprime un rastreo: una pared de texto rojo que parece aterrador y en realidad es un regalo. Léelo de abajo hacia arriba: la última línea nombra el error y las líneas superiores rastrean dónde ocurrió.

Traceback (most recent call last):
File "tax.py", line 2, in total_with_tax
return price + (price * tax_rate)
TypeError: can't multiply sequence by non-int of type 'float'

La conclusión es toda la historia: algo era una cadena (str) cuando debería haber sido un número: un price apareció como "100" (texto) en lugar de 100.0. No es necesario que lo arregles tú mismo; necesitas leerlo lo suficientemente bien para decirle al agente lo que está mal: "el precio llega como texto, no como un número. Maneja eso". Una descripción precisa obtiene una solución precisa. (La depuración tiene su propia fase: Programación en la era de la IA, Fase 4.)

Nunca vuelvas a preguntar a ciegas

El hábito más caro en la codificación de IA es presionar "intentar de nuevo" ante un error que no leíste. El agente generará alegremente una respuesta incorrecta diferente. Lee el rastreo, comprenda el problema real y luego descríbalo. Un mensaje informado vence a diez ciegos.

El puñado de errores que realmente encontrarás

No memorizas las correcciones. Reconoce la categoría de esa última línea y se la describe al agente. Estos seis cubren casi todo lo que ve un principiante cuando ejecuta el código generado:

La última línea dice...Lo que normalmente significaQué decirle al agente
ModuleNotFoundError / ImportErrorUn paquete no está instalado o un nombre está mal escrito"X no está instalado; agréguelo con uv"
NameErrorSe utiliza un nombre que nunca fue definido (a menudo un error tipográfico)"y se utiliza pero nunca se define: ¿error tipográfico?"
TypeErrorEl tipo de valor incorrecto: texto donde se esperaba un número, etc."Un número llega como texto: conviértelo"
AttributeErrorPedirle a un objeto algo que no tiene (note.titel)"este objeto no tiene atributo titel; probablemente sea un error tipográfico"
KeyErrorPedir un dict por una clave que no está en él"la clave 'x' no está en el diccionario: maneje el caso que falta"
IndexErrorSolicitar una lista para un puesto más allá de su fin"la lista es más corta de lo que supone el código"

La meta-habilidad es la misma que la configuración (Concepto 3): tú no es quien corrige el error, tú es quien lo lee y lo nombra con precisión. Un nombre preciso obtiene una solución precisa; "se rompió" tiene otra suposición.

17. De un objetivo vago a piezas especificables

El Concepto 16 mostró cómo especificar y verificar una unidad. Pero sus propios proyectos no llegan como una función ordenada. Llegan como una frase vaga: "constrúyeme una herramienta que resuma mis notas". No puedes escribir una sola prueba para eso. La habilidad que convierte una oración en código generado es la descomposición: dividir el objetivo en pedazos pequeños, cada uno de ellos lo suficientemente pequeño como para dar una firma mecanografiada y una prueba. Esta es la parte que el agente no puede hacer por ti, porque es donde tú decide qué es realmente la cosa.

Aquí está el movimiento, y es el mismo cada vez.

Decomposition: a one-sentence goal breaks into several small units, each given a typed signature and a failing test, which are then generated, verified, and wired together. 1. Di el objetivo en una oración. "Lee mis notas e imprime cuántas están hechas y cuáles no".

2. Enumera los pasos que harías a mano. Escribe los verbos: carga las notas → cuenta las realizadas → encuentra los títulos pendientes → resúmelos en una línea → imprime. Cada verbo es una unidad candidata.

3. Asigne a cada unidad una firma mecanografiada: entrada a salida. Esta es la especificación. Aún no hay cadáveres; el agente los escribe.

def load_notes(path: str) -> list[Note]: ...      # text file -> list of notes
def count_done(notes: list[Note]) -> int: ... # notes -> how many are done
def pending_titles(notes: list[Note]) -> list[str]: ... # notes -> titles not done
def summarize(notes: list[Note]) -> str: ... # notes -> one summary line

4. TDG cada unidad, en orden. Cada línea anterior es ahora exactamente un ciclo del Concepto 16: escribe la prueba fallida, haz que el agente genere el cuerpo, verifique. Por ejemplo, summarize es pequeño y comprobable:

def test_summarize() -> None:
notes = [Note(title="groceries", done=True), Note(title="call sara", done=False)]
assert summarize(notes) == "1 of 2 done; pending: call sara"

5. Conéctelos y prueba todo el flujo. Pídele al agente que escriba un main() que indique las piezas en orden y luego escribe una prueba para obtener el resultado de un extremo a otro. Hecho.

Observa lo que sucedió: una frase vaga se convirtió en cuatro pequeños contratos verificables de forma independiente. El agente escribió cada línea de código real. Pero encontraste las piezas y definiste lo que promete cada una. Esa descomposición inicial es el 10% humano que hace que el 80% del agente sea confiable.

Usa al agente para intercambiar ideas, pero sea dueño de los contratos

Puede pedirle al agente que le ayude a encontrar las unidades: "Quiero crear una herramienta que resuma mis notas. ¿Qué 3 a 5 funciones necesitaría, con sus entradas y salidas?" Esa es una excelente lista de inicio. Pero decides las firmas finales y escribes las pruebas. Nunca permita que el agente descomponga el problema y verifica su propia respuesta, o perderá su control independiente.

Una heurística confiable: si es difícil escribir una prueba para una unidad, está haciendo demasiado. Divídalo. Una función que no puede probar es una función que no puede verificar, lo que significa que tampoco puede confiar en lo que el agente generó para ella. La capacidad de prueba y la buena descomposición son la misma habilidad.

Este es el puente entre "Puedo verificar una función" y "Puedo construir todo con IA". Así es exactamente como crece el proyecto SmartNotes del libro: una pieza descompuesta y probada a la vez. Practicarás esto en el mini-capstone del Proyecto 5, luego desde cero sin andamios en el Proyecto 6.

Un mensaje que puedes reutilizar para cualquier proyecto

Una vez que hayas descompuesto un objetivo, esta es una plantilla que puedes pegar en Claude Code o OpenCode cada vez. Se integra en toda la disciplina de este curso: pruebas primero, su aprobación antes del código, verificación al final:

I want to build: [your one-sentence goal]

First, break it into 3–5 small functions or classes.
For each unit, propose ONLY:
1. a typed signature (inputs and output)
2. expected behavior in one line
3. edge cases to consider
4. pytest tests

Do NOT write any implementation yet. Wait for me to approve the tests.

After I approve, generate the implementation to pass those tests.
Then run pytest, pyright, and ruff, and show me only the
changed files and the test results.

Las dos palabras de carga son SÓLO y NO: impiden que el agente avance y escribe código (y sus propias pruebas) antes de que tú haya decidido qué significa "correcto". Tú mantiene el control de las especificaciones; el agente escribe a máquina.


Parte 5: Juicio

Cuándo NO apoyarse en la IA y cómo verificar lo que no se puede leer por completo

La fluidez lectora tiene un límite, y ser honesto al respecto es en sí mismo una habilidad.

  • El código sensible a la seguridad no es negociable. Todo lo relacionado con contraseñas, claves API, pagos o datos de usuario se lee atentamente e, idealmente, lo revisa alguien que conoce el dominio. La IA escribe con confianza código inseguro. Si no puede verificarlo, no lo envíe. (Consulte Programación en la era de la IA, Fase 8 para una revisión de seguridad).
  • Cuando realmente no puedas leerlo, apóyate más en las pruebas, no en la fe. Si una función generada está más allá de tu nivel actual, tus comprobaciones pytest se vuelven más importantes, no menos: son la parte que puedes verificar. Las pruebas ecológicas de los insumos que tú elegiste son pruebas reales; "se ve bien" no lo es.
  • Los cambios pequeños y obvios a veces son más rápidos a mano. Cambiar el nombre de una variable o corregir un número puede ser más rápido de hacer uno mismo que de describirlo. Reconocer estos momentos viene con la práctica.

Crea un equipo rojo con tus propias pruebas

Sus pruebas son la única verificación que tú controlas completamente, por lo que una prueba débil es peor que ninguna prueba, porque da una confianza falsa. Cuando el agente genera un código que no puede leer por completo (un validador Pydantic complicado, un bloque async), sus pruebas transportan toda la carga. Hazlos conflictivos:

  • Nunca dejes que el agente escribe las pruebas que su propio código debe pasar. Ese es el único antipatrón que derrota silenciosamente a todo lo demás en este curso: si la IA escribe tanto el código como la verificación, no tienes ninguna señal independiente: solo el agente está de acuerdo consigo mismo. Tú escribe las pruebas o, como mínimo, lee y es dueño de cada afirmación. Por supuesto, pregunta "¿qué casos extremos me faltan?". Luego, decida tú mismo cuáles le importan.
  • Nunca permita que el agente debilite una prueba para hacerla pasar. Cuando una prueba falla, el agente a veces la "arreglará" cambiando la prueba en lugar del código: aflojando una aserción, eliminando un caso límite, reduciendo un valor esperado. Eso cambia de rojo a verde mientras deja el error en su lugar. Esté atento y no lo permita a menos que haya decidido que la prueba en sí fue realmente incorrecta. La prueba es la especificación; el agente no puede reescribir la especificación para adaptarla a su código.
  • Prueba los fracasos, no solo el camino feliz. Pregunta a cada unidad: ¿qué entrada rompería esto? Lista vacía, cero, un número negativo, falta una clave, texto donde se esperaba un número. El error en el Proyecto 4 se escondió exactamente en el caso en que nadie lo probó.
  • Si no se te ocurre ninguna prueba para ello, es que aún no lo entiendes. Y ciertamente no puedes verificar la versión del agente. Esa es su señal para descomponerse aún más (Concepto 17) o pedirle al agente que le explique el código línea por línea antes de aceptarlo.

Una heurística vaga que debes conservar: las pruebas verdes demuestran que tu código hace lo que tus pruebas dicen. No más. La calidad de su verificación es exactamente la calidad de sus pruebas. (Los archivos, la biblioteca estándar, el ecosistema de paquetes, la depuración más profunda y la revisión de seguridad real se dejan deliberadamente a Programación en la era de la IA. Este curso intensivo le brinda el criterio; esa parte le brinda la profundidad).

Revisa la diferencia antes de aceptarla.

Cuando trabajas en Claude Code o OpenCode, el agente no solo responde. Cambia archivos. Leer el código es la mitad del trabajo; la otra mitad está leyendo lo que cambió. Antes de aceptar cualquier lote de cambios generados, consulte esta lista:

  1. ¿Qué archivos cambiaron? Una solicitud para corregir una función no debería afectar silenciosamente a cinco archivos.
  2. ¿Cambió las pruebas? Si sus pruebas fueron editadas, averigüe por qué antes que nada (consulte el antipatrón arriba).
  3. ¿Agregó dependencias? Los paquetes nuevos significan código nuevo que no escribiste ejecutándose en tu máquina. Asegúrate de que cada uno sea real y necesario.
  4. ¿Tocó algo sensible? Secretos, claves, autenticación, pagos, datos de usuario: alguien que conoce el dominio los lee atentamente o los revisa.
  5. ¿Pasaron pytest, Pyright y Ruff? El verde en los tres es el piso, no el techo.
  6. ¿Puedes explicar la función o clase principal en un inglés sencillo? Si no puedes, no puedes verificarlo: pídele al agente que te guíe línea por línea antes de aceptar.

Este es un hábito rápido, no una ceremonia. Pero "aceptar todo" sin leer la diferencia es la forma en que un pequeño cambio incorrecto pasa desapercibido en un proyecto en funcionamiento.

El resumen de todo este curso: el agente trae el código; tú juzga si es correcto. Ese juicio se basa en la lectura con fluidez y en las pruebas que tú mismo redactó. Ninguno de los dos es opcional y tampoco es difícil una vez que hayas practicado el bucle.


Parte 6: Proyectos de práctica

Leer sobre el bucle no es lo mismo que ejecutarlo. Estos seis proyectos lo llevan a través de PRIMM-AI+ en orden: desde leer el código hasta probarlo, crear el suyo propio, verificar el código estilo agente real con un error oculto, crear una pequeña herramienta de extremo a extremo que usa todos los conceptos a la vez y, finalmente, crear una a partir de un objetivo de una sola oración sin ningún tipo de andamiaje. Hazlos en tu sesión Claude Code o OpenCode, en orden; cada uno asume las habilidades del anterior.

Cada proyecto te indica el objetivo y las habilidades que ejercita, y luego te entrega un introductor. Pruébelo tú mismo primero: escribe su predicción, escribe sus pruebas, avise al agente. Y solo entonces abre la solución. Las soluciones no están ahí para copiarlas: el agente puede generar el código por ti de todos modos. Están ahí para que puedas comprobar que tus especificaciones y tus pruebas fueron correctas. Esa es la habilidad que se califica.

Cómo utilizar las soluciones

El código de referencia es la parte menos importante de cada solución. Lo que importa es: ¿capturaron sus pruebas lo que significa "correcto"? ¿Predijiste la salida correctamente? ¿Podrías leer el resultado y decir que era correcto? Si sus pruebas pasan con el código de referencia, especificó bien el problema. Esa es la victoria.

Proyecto 1: Leer y predecir (Predecir · Ejecutar · Investigar)

Skills: funciones de lectura, comprensión y len; predecir la salida antes de ejecutar.

Iniciador. No ejecutes esto todavía. Léelo y anota lo que producirá cada una de las tres líneas print:

def shout(text: str) -> str:
return text.upper() + "!"

names: list[str] = ["ada", "alan", "grace"]
greetings: list[str] = [shout(n) for n in names if len(n) > 3]

print(len(names))
print(greetings)
print(shout("hi"))

Ahora ejecútelo en su sesión y compare. Cuando su predicción estuvo equivocada, pregúntele al agente "¿por qué la línea X produjo eso?". Esa brecha es la lección.

Solución
3
['ALAN!', 'GRACE!']
HI!
  • len(names)3: tres elementos en la lista.
  • greetings → solo los nombres de más de 3 letras pasan el filtro if len(n) > 3. "ada" es exactamente 3 (falla), "alan" es 4 y "grace" es 5 (aprobado). Se grita cada uno, dando ['ALAN!', 'GRACE!'].
  • shout("hi")"HI!": en mayúsculas, con ! agregado.

Si lees la comprensión como "grita cada nombre, para cada nombre en los nombres, si tiene más de 3 letras", lo lees correctamente.

Proyecto 2: su primer ciclo TDG en una función (Make)

Skills: escribir pruebas assert como una especificación, solicitar al agente y verificar con pytest.

Objetivo. Crea una función initials(full_name: str) -> str que devuelve las iniciales mayúsculas de un nombre: "ada lovelace""AL".

Inicio. Escribe las pruebas primero, en test_initials.py, antes de que exista cualquier implementación. Cubra el caso normal y al menos dos casos extremos (un solo nombre; espacios adicionales). Luego pregunta a tu agente:

Lee test_initials.py. Crea initials.py con una función initials(full_name: str) -> str que supere todas las pruebas. Luego ejecuta pytest y muéstrame el resultado.

Lee el código que genera antes de confiar en los cheques verdes.

Solución

Sus pruebas (la parte importante) podrían verse así:

from initials import initials

def test_two_names() -> None:
assert initials("ada lovelace") == "AL"

def test_many_names() -> None:
assert initials("grace brewster murray hopper") == "GBMH"

def test_single_name() -> None:
assert initials("alan") == "A"

def test_extra_spaces() -> None:
assert initials(" extra spaces ") == "ES"

Una implementación de referencia que los supera todos:

def initials(full_name: str) -> str:
return "".join(part[0].upper() for part in full_name.split())

full_name.split() divide el texto en espacios (e ignora los adicionales), part[0] toma la primera letra de cada pieza, .upper() la pone en mayúscula y "".join(...) las pega. Si tú escribiste la prueba extra_spaces, tú mismo verificó el complicado caso: ese es exactamente el juicio que el agente no puede proporcionar.

Proyecto 3: TDG en una clase (Marca)

Skills: leer y especificar una clase, métodos que cambian el estado del objeto, probar el comportamiento del objeto.

Objetivo. Construir un pequeño TaskList: la semilla de algo como el SmartNotes del libro. Puede agregar tareas, marcar una como completada e informar cuántas aún están sin terminar.

Inicio. Escribe las pruebas primero. Decida cómo se llaman los métodos y qué devuelven. Ese es el diseño. Un punto de partida:

def test_task_flow() -> None:
tasks = TaskList()
tasks.add("write tests")
tasks.add("call agent")
assert tasks.remaining() == 2
tasks.complete("write tests")
assert tasks.remaining() == 1

Luego solicite al agente que implemente una clase TaskList que haz que la prueba pase y verifique.

Solución

Una implementación de referencia:

class TaskList:
def __init__(self) -> None:
self.tasks: dict[str, bool] = {} # task name -> done?

def add(self, name: str) -> None:
self.tasks[name] = False

def complete(self, name: str) -> None:
if name in self.tasks: # only complete a task that exists
self.tasks[name] = True

def remaining(self) -> int:
return sum(1 for done in self.tasks.values() if not done)

La clase almacena tareas en un dict que asigna cada nombre a un indicador done. remaining() cuenta los que aún están configurados en False. Observa cómo la prueba impulsó el diseño: decidió los nombres de los métodos y lo que devuelve remaining(), antes de que existiera cualquier código.

Detecta el error silencioso tú mismo. ¿Qué debería hacer complete("a task I never added")? La primera versión de un agente a menudo escribe self.tasks[name] = True sin protección if name in self.tasks, lo que silenciosamente agrega una nueva tarea marcada como completada, inventando datos que nadie pidió. Ese es exactamente el comportamiento plausible pero incorrecto que expone una prueba:

def test_completing_unknown_task_does_nothing() -> None:
tasks = TaskList()
tasks.add("real task")
tasks.complete("typo task") # not a real task
assert tasks.remaining() == 1 # still one; nothing was invented

Extensión: pídele a tu agente que haz de cada tarea un modelo Pydantic Task con una marca de tiempo created_at, luego agrega una prueba de que un TaskList nuevo tiene remaining() == 0.

Proyecto 4: encontrar el error en el código del agente (Investigar · Modificar)

Skills: reconocer los conceptos de energía (Pydantic, generadores), leer críticamente, escribir una prueba que detecte un error real.

Esto es lo más parecido a tu trabajo real: el agente te entrega un código que parece plausible y tú tienes que detectar lo que está mal. Se supone que la siguiente función devuelve solo los títulos de las notas que están terminadas. Pero tiene un error.

from collections.abc import Iterator
from pydantic import BaseModel

class Note(BaseModel):
title: str
done: bool

def completed_titles(notes: list[Note]) -> Iterator[str]:
for note in notes:
yield note.title

Tu tarea, en orden:

  1. Investigar. En lenguaje sencillo, di qué debe hacer cada línea. (¿Qué es el modelo Note? ¿Qué te dice Iterator[str]? ¿Qué hace yield?)
  2. Prueba. Escribe una prueba pytest que fije el comportamiento previsto: solo se devuelven las notas completadas. Ejecútelo. Debería fallar y detectar el error.
  3. Modificar. Ahora que su prueba se define como correcta, solicite al agente que corrija completed_titles y vuelve a ejecutarla hasta que la prueba esté en verde.
Solución

El error: la función genera cada título de nota, ignorando por completo done. Nunca revisa la bandera.

Una prueba que lo detecta:

def test_only_completed() -> None:
notes = [Note(title="a", done=True), Note(title="b", done=False)]
assert list(completed_titles(notes)) == ["a"]

Contra el código del error, esto falla porque devuelve ["a", "b"]: prueba de que el error es real, no una corazonada.

La solución es una línea: una verificación done antes de ceder:

def completed_titles(notes: list[Note]) -> Iterator[str]:
for note in notes:
if note.done:
yield note.title

El objetivo de este proyecto: el error era invisible a simple vista y obvio durante una prueba. "Se ve bien" lo habría enviado. Una prueba que escribiste lo captó. Ese es el curso completo en un solo ejercicio.

Proyecto 5: Mini-capstone: una herramienta de Notas, de principio a fin (todo el bucle)

Skills: todo, un modelo Pydantic, una clase con estado, un generador, sugerencias de tipo, un resumen de cadena f y un conjunto de pruebas, creado como un ciclo TDG. Este es un ensayo reducido del SmartNotes del libro.

Objetivo. Crea un pequeño NoteBook que contenga notas (cada una con un título, un cuerpo y una marca de finalización), le permita agregar notas y marcarlas como completas, transmitir las que aún están pendientes e imprimir un resumen de una línea como 2 notes, 1 done, pending: call sara.

Inicio: diseñarlo mediante pruebas. Este es el verdadero ejercicio: antes de escribir o generar cualquier implementación, escribe un test_notebook.py que determine el comportamiento que desea. Decida los nombres de los métodos y lo que debería decir summary(). Un esqueleto ante el cual reaccionar:

from notebook import NoteBook

def test_summary_flow() -> None:
nb = NoteBook()
nb.add("groceries", "milk, eggs")
nb.add("call sara", "about the trip")
assert nb.summary() == "2 notes, 0 done, pending: groceries, call sara"
nb.complete("groceries")
assert nb.summary() == "2 notes, 1 done, pending: call sara"

def test_pending_is_a_stream() -> None:
nb = NoteBook()
nb.add("a", "x")
nb.add("b", "y")
nb.complete("a")
assert [n.title for n in nb.pending()] == ["b"] # pending() yields, like a generator

Luego ejecuta el ciclo completo:

  1. Ejecuta pytest. Falla (aún no hay notebook.py). Bien: esa es tu especificación, fallar a propósito.
  2. Indique a tu agente: "Lee test_notebook.py. Crea notebook.py con un modelo Note Pydantic (título, cuerpo, hecho) y una clase NoteBook que supere todas las pruebas: add, complete, un generador pending() y un summary() devuelve la cadena exacta que esperan las pruebas. Luego ejecuta pytest y muéstrame el resultado."
  3. Lee lo que generó. ¿Puede señalar el modelo Pydantic, el estado de clase, el yield en pending() y la cadena f en summary()? En caso afirmativo, ha leído un código de agente real. Ejecuta pyright y ruff en él también.
  4. Repita cualquier error leyéndolo, sin volver a solicitarlo a ciegas.
Solución

Una implementación de referencia que pasa ambas pruebas:

from collections.abc import Iterator
from pydantic import BaseModel

class Note(BaseModel):
title: str
body: str
done: bool = False

class NoteBook:
def __init__(self) -> None:
self.notes: list[Note] = []

def add(self, title: str, body: str) -> None:
self.notes.append(Note(title=title, body=body))

def complete(self, title: str) -> None:
for note in self.notes:
if note.title == title:
note.done = True

def pending(self) -> Iterator[Note]: # a generator: yields one note at a time
for note in self.notes:
if not note.done:
yield note

def summary(self) -> str:
total = len(self.notes)
done = sum(1 for n in self.notes if n.done)
pending_titles = [n.title for n in self.pending()]
return f"{total} notes, {done} done, pending: {', '.join(pending_titles)}"

Todos los conceptos del curso se muestran aquí: un modelo Pydantic (Note) con sugerencias de tipo y un estado predeterminado, una clase (NoteBook), un método que muta el atributo de un objeto (complete), un generador (pending) que yield, una comprensión y sum(...), y una cadena f que construye el resumen.

Conviértalo en una CLI real (el puente hacia el curso Programación en la era de la IA). El núcleo probado anteriormente es la parte difícil; convertirlo en una herramienta de línea de comandos es una capa delgada en la parte superior. Pídele a tu agente que agrega un main() que lee comandos como add, done y list desde la terminal y llame a estos métodos. Luego pídele que escriba una prueba más para cualquier lógica nueva. Ese último paso, una CLI funcional con un conjunto de pruebas aprobadas detrás, tiene exactamente la forma de SmartNotes, solo que más pequeño.

Decida tú mismo un caso límite. ¿Qué debería decir summary() cuando no hay nada pendiente? La referencia deja un pending: al final. ¿Es eso correcto? Escribe una prueba que codifique su decisión y luego haz que el agente la satisfaga. Decidir qué significa "correcto" aquí y fijarlo con una prueba es todo el trabajo.

Proyecto 6 — Por tu cuenta: sin arranque, sin pruebas (descompóngalo tú mismo)

Skills: Concept 17 sin las ruedas de apoyo. Hasta ahora, cada proyecto te ha entregado un esqueleto de prueba o una firma. Éste te da sólo una frase.

Objetivo. "Crear una herramienta que tome un párrafo de texto e imprima las tres palabras más comunes."

Eso es todo lo que obtienes. Ni firmas, ni pruebas, ni pistas sobre las piezas. Tu trabajo es todo el frente 10%:

  1. Descomponer. Escribe los pasos que harías a mano y convierte cada uno en una firma mecanografiada. (¿Cómo se divide el texto en palabras? ¿Quitar la puntuación? ¿Cuentarlas? Clasificarlas?)
  2. Especificación. Para cada pieza, escribe una prueba pytest fallida que defina "correcto": antes de generar cualquier cosa.
  3. Generar y verificar. Haz que el agente implemente cada unidad en comparación con sus pruebas; ejecuta pytest, pyright, ruff; iterar.
  4. Conéctelo a un report() y prueba todo el flujo.

No existe una única respuesta correcta: sólo descomposiciones donde cada pieza es pequeña y comprobable. Esa es la habilidad que se califica.

Solución (una descomposición válida; la suya puede diferir)

Un desglose razonable en cuatro unidades pequeñas y comprobables de forma independiente:

def clean(text: str) -> list[str]:
# lowercase, drop punctuation, split into words
cleaned = "".join(c.lower() if c.isalnum() or c.isspace() else " " for c in text)
return cleaned.split()

def tally(words: list[str]) -> dict[str, int]:
counts: dict[str, int] = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
return counts

def top_n(counts: dict[str, int], n: int) -> list[tuple[str, int]]:
return sorted(counts.items(), key=lambda pair: pair[1], reverse=True)[:n]

def report(text: str, n: int) -> str:
pairs = top_n(tally(clean(text)), n)
return ", ".join(f"{word} ({count})" for word, count in pairs)

Y el tipo de pruebas que deberías haber escrito primero:

def test_clean_strips_punctuation() -> None:
assert clean("Hi, hi! Bye.") == ["hi", "hi", "bye"]

def test_tally_counts() -> None:
assert tally(["hi", "hi", "bye"]) == {"hi": 2, "bye": 1}

def test_report_picks_top_two() -> None:
assert report("the cat sat on the mat the cat", 2) == "the (3), cat (2)"

Una decisión que vale la pena tomar a propósito: cuando dos palabras cuentan lo mismo, ¿cuál viene primero? El sorted de Python es estable, por lo que los empates vuelven al orden de primera aparición aquí. Pero deberías decidirlo deliberadamente y fijarlo con una prueba, no descubrirlo por accidente. (Si no pensó en los enlaces en absoluto, esa es una brecha que sus pruebas deberían haber surgido).

Si su descomposición tenía diferentes piezas (digamos, una sola función word_frequencies) pero cada pieza se podía probar de forma independiente y sus pruebas pasaron, lo hizo bien. La calificación no coincide con este código: se trata de si convirtió un objetivo de una oración en contratos comprobables por su cuenta. Esa es exactamente la habilidad en la que te apoyarás para cada proyecto que crees con IA después de este.

Dónde ir más grande

Estos son calentamientos. El proyecto de práctica real es SmartNotes en Programación en la era de la IA. Tú desarrolla una aplicación en nueve fases utilizando este ciclo exacto y luego crea una segunda (QuizForge) desde cero sin orientación para demostrar que la habilidad es suya.


¿Qué sigue?

Ahora puede leer las formas centrales que componen la mayor parte de Python (valores, funciones, colecciones, flujo de control y clases), reconocer los cinco conceptos de poder que llenan el código de agente y ML, ejecutar un ciclo Test-Driven Generation completo en Claude Code o OpenCode, dividir un objetivo vago en partes especificables y haber practicado todo ello en seis proyectos. Ésa es la alfabetización que asume el resto del libro.

¿Has pasado? Un autocontrol

Este curso ha funcionado si ahora puedes realizar los siete sin notas. Si alguno se siente inestable, revise el concepto entre paréntesis antes de continuar:

  1. Lee la firma de una función y explique sus entradas y salidas en inglés sencillo. (Concepto 5)
  2. Escribe al menos tres pruebas pytest para una unidad antes de que exista cualquier código. (Conceptos 5, 16)
  3. Pídele a un agente de IA que implemente código en esas pruebas, utilizando una firma mecanografiada. (Conceptos 10, 16)
  4. Ejecuta pytest, Pyright y Ruff y lee lo que cada uno le dice. (Concepto 3)
  5. Lee un rastreo de abajo hacia arriba y describe el problema con precisión. (Concepto 16)
  6. Detecte un error plausible pero incorrecto en el código generado por IA. (Proyecto 4)
  7. Descomponga un objetivo vago de una sola oración en unidades comprobables. (Concepto 17, Proyecto 6)

Si puede hacer los siete, puede sentarse con Claude Code o OpenCode y enviar un programa Python pequeño y probado que realmente comprenda. Ese es todo el objetivo.

Desde aquí:

  • Build AI Agents: donde los modelos Pydantic, async/await y las sugerencias de tipo que acaba de aprender a reconocer se convierten en el material cotidiano del código del agente.
  • Postgres for AI: lectura del código que almacena y recupera los datos de tus agentes.
  • Building a Digital FTE: ensamblar todo en un trabajador de IA que funcione.
  • Programación en la era de la IA: el curso profundo completo. Tú construye SmartNotes en nueve fases, pasando del lector al arquitecto, poseyendo más del ciclo TDG en cada paso.

No estás aprendiendo a escribir código. Estás aprendiendo a dirigir y verificar los sistemas que lo escriben. La lectura siempre fue la mitad más difícil. Y acabas de empezar.


glosario de 60 segundos

TérminoInglés sencillo
PRIMM-AI+Predecir · Ejecutar · Investigar · Modificar · Crear: el método de lectura primero de este curso, con el agente como socio y las pruebas como la verdad
TDD → TDGDesarrollo basado en pruebas: escribe la prueba fallida y luego escribe el código. En la era de la IA, se convierte en Test-Driven Generation: tú escribe la prueba fallida, el agente escribe el código, tú verifica que pase
TDGTest-Driven Generation: escribe primero la prueba fallida, el agente genera el código, tú verifica
assertUna afirmación de una línea como assert x == 5: no hace nada si es verdadera, falla ruidosamente si es falsa. El átomo a partir del cual se construye cada prueba
Escriba/escribe sugerenciaUna etiqueta que indica qué tipo de datos es algo (str, int, float, bool) y una instrucción precisa para el agente.
Función/firmaUn bloque reutilizable con nombre; su primera línea es el contrato de insumos y productos.
lista/dict/conjunto/tuplaLos cuatro contenedores que agrupan datos; dict (pares etiquetados) es el que más leerás
Clase/objetoUna clase es un modelo; un objeto (instancia) es una cosa construida a partir de él. object.attribute lee tus datos; object.method() le pide que actúe
self/atributo/métodoself es "este objeto" dentro de una clase; un atributo son los datos que contiene; un método es una función que vive en la clase y actúa sobre el objeto
ComprensiónUn bucle for doblado en una línea para crear una nueva lista
f-cuerdaTexto con f al frente; cualquier cosa dentro de {...} se reemplaza por su valor (f"{name}")
Generador / yieldDevuelve los elementos uno a la vez para mantener la memoria plana: un flujo, no una pila.
with (administrador de contexto)Abre algo, lo usa y lo cierra de forma segura incluso en caso de error.
async / awaitCódigo creado para hacer muchas cosas lentas (como llamadas API) al mismo tiempo
Dunder (__call__, __init__)Métodos de doble subrayado que hacen que sus objetos actúen como objetos nativos Python
Decorador (@name)Una etiqueta encima de una función o clase que le agrega comportamiento.
PydanticValida datos estructurados y genera automáticamente los esquemas JSON que los LLM utilizan para llamar a herramientas
pytest / Pyright / Ruff / uvSus herramientas de verificación: ejecuta pruebas / verifica tipos / verifica estilo / administre Python
RastreoInforme de errores de Python: léalo de abajo hacia arriba; la última línea nombra el problema

Ayuda para el estudio de tarjetas didácticas


Pon a prueba tu comprensión

Checking access...