Clase 1 — ¿Qué es un programa?
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?
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.
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.
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.
Abre DeepL y traduce la siguiente frase al ruso.
"La muestra presenta un sesgo significativo en la estimación del error estándar."
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 2025Un 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.
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.
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.
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.
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.")
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?
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?
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?
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.
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.
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.
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.
El intérprete de Python es conversacional, pero no es indulgente. Para cada bloque de abajo sigue estos tres pasos:
— 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?
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.
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.
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.
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.
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.
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.
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}%")
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?
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.
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.
def
define; el código sin sangría al final es el que manda ejecutar.
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%.
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.
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])]
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.
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.
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.
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:
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.
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 —
— Ahora en Python —
def media(numeros):
total = len(numeros)
suma = sum(numeros)
return suma / total
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.
Una posible solución:
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.
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.
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.
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 —
— Versión A: prompt vago —
— Versión B: prompt mejorado —
— Versión C: prompt desde pseudocódigo —
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.
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.
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.
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.
Tres tareas para completar antes de la próxima clase. No son opcionales: la Clase 2 parte de que las has hecho.
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.
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?
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.
Si usas Windows, Mac o Linux las instrucciones difieren ligeramente. El documento cubre los tres casos.
↗ Introducción JupyterLab