Las entrevistas de Python backend cubren internos del lenguaje, programación async, Django o FastAPI, y patrones de acceso a base de datos. Aquí están las preguntas más comunes con respuestas modelo. Middle: comprensión más profunda, optimización y situaciones reales de trabajo.
1
¿Qué previene realmente el GIL, y cuándo igual ayudan los hilos?
Respuesta
El Global Interpreter Lock permite que solo un hilo ejecute bytecode de Python a la vez, así que el código Python puro nunca corre en paralelo a través de núcleos. Los hilos igual ayudan siempre que el trabajo sea esperar en vez de calcular — llamadas de red, disco, base de datos — porque el lock se libera durante I/O bloqueante. Para trabajo limitado por CPU necesitas procesos, una extensión en C que suelte el GIL, o mover la parte caliente fuera de Python.
2
¿Qué hace realmente await, y cuándo async no tiene sentido?
Respuesta
await devuelve el control al event loop para que pueda correr otra cosa hasta que la operación esperada se complete; no crea un hilo y nada corre en paralelo. Async no tiene sentido cuando el trabajo está limitado por CPU, porque un cómputo largo bloquea el loop y a cada otra tarea con él. Tampoco tiene sentido si alguna librería en el camino es síncrona — un driver de base de datos bloqueante detiene todo el loop.
3
Escribe un decorador. ¿Por qué necesita functools.wraps?
Respuesta
Un decorador es una función que toma una función y devuelve un reemplazo, usualmente un closure que llama al original. Sin functools.wraps el reemplazo lleva su propio nombre y docstring, así que la función decorada se reporta a sí misma como 'wrapper' — lo que rompe la introspección, help(), y cualquier framework que enrute por nombre de función. wraps copia los metadatos a través.
4
Tienes un problema N+1 en el ORM. ¿Cómo lo encuentras y arreglas?
Respuesta
Lo encuentras mirando el log de consultas o la debug toolbar y viendo una consulta por fila de una lista. La causa es lazy loading dentro de un loop. select_related lo soluciona para foreign keys hacia adelante con un join; prefetch_related lo soluciona para relaciones inversas y many-to-many con una segunda consulta y un match en memoria. La trampa es arreglar el síntoma cacheando el resultado en vez de la consulta.
5
¿Cuándo devolverías un generador en vez de una lista?
Respuesta
Cuando el caller itera una vez y los datos no necesitan caber en memoria — leer un archivo grande, streaming de resultados de consulta, un pipeline de transformaciones. El costo es que un generador se consume: no puedes tomar su longitud, indexarlo, o iterarlo dos veces sin materializarlo. Devolver uno desde una API pública sorprende a los callers que esperan una secuencia, así que debería ser una decisión documentada.
6
¿Qué garantiza un context manager?
Respuesta
Que __exit__ corre ya sea que el bloque termine normalmente o lance una excepción, por eso los file handles, locks y transacciones pertenecen a uno. Escrito con contextlib.contextmanager, el código antes de yield es setup y el código después es teardown — pero solo si el teardown está en un finally, si no una excepción lo salta. La garantía es sobre la limpieza, no sobre suprimir el error.
7
¿Qué mockeas en un test, y qué no?
Respuesta
Mockea lo que no posees y no puedes controlar: APIs de terceros, el reloj, la aleatoriedad, el envío de correos. No mockees tu propia lógica de dominio, porque entonces el test afirma que tu mock se comporta como lo escribiste. Mockear la base de datos usualmente también es un error — una transacción revertida después de cada test da comportamiento real a bajo costo, y los bugs del ORM son exactamente los que los mocks esconden.