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.
Cada pregunta viene con una respuesta modelo con la que puedes comparar la tuya.
1
¿Qué es el GIL y cómo afecta el multithreading?
Respuesta
El Global Interpreter Lock permite que solo un hilo ejecute bytecode de Python a la vez en CPython, así que los hilos nunca corren código Python en paralelo a través de núcleos. Los hilos igual ayudan para trabajo limitado por I/O porque el GIL se libera durante llamadas bloqueantes. Para trabajo limitado por CPU necesitas multiprocessing, una extensión en C que libere el GIL, o un runtime distinto.
2
¿Cuál es la diferencia entre una lista y una tupla? ¿Cuándo usas cada una?
Respuesta
Las listas son mutables y las tuplas inmutables, lo que hace a las tuplas hasheables y usables como claves de diccionario. Las tuplas son ligeramente más rápidas y le señalan al lector que la colección es un registro fijo y no una secuencia que crece. Usa una lista cuando el contenido cambia y una tupla para datos heterogéneos fijos como coordenadas o un par devuelto.
3
¿Qué es un decorador? Escribe uno que mida el tiempo de ejecución.
Respuesta
Un decorador es un callable que toma una función y devuelve un reemplazo, usado para agregar comportamiento sin tocar el cuerpo original. Un decorador de timing envuelve la llamada: registra perf_counter antes, invoca la función, registra después, loguea el delta, y devuelve el resultado. Siempre aplica functools.wraps a la función interna para que el nombre original, docstring, y firma sobrevivan la introspección.
4
Explica la diferencia entre un generador y una función normal. ¿Por qué necesitamos yield?
Respuesta
Una función normal calcula todo y retorna una vez; un generador se suspende en cada yield y retoma donde quedó, produciendo valores de forma perezosa. Eso significa memoria constante sin importar cuántos elementos se produzcan, así que puedes iterar un archivo de varios gigabytes o una secuencia infinita. yield es lo que convierte a la función en una máquina de estados que el intérprete puede pausar y reanudar.
5
¿Qué son *args y **kwargs? Da un ejemplo de uso.
Respuesta
*args recolecta argumentos posicionales extra en una tupla y **kwargs recolecta argumentos de palabra clave extra en un dict. Se usan cuando una función debe aceptar una firma arbitraria — más a menudo en decoradores y wrappers que reenvían todo al callable envuelto. El uso espejo es el unpacking: llamar a f(*items, **options) esparce una secuencia y un mapping en argumentos.
6
¿Cuál es la diferencia entre multiprocessing, threading, y asyncio?
Respuesta
Threading da concurrencia dentro de un proceso y ayuda solo con I/O por el GIL. Multiprocessing genera intérpretes separados con paralelismo real, al costo del arranque de procesos y comunicación entre procesos — la elección correcta para trabajo limitado por CPU. asyncio es concurrencia cooperativa de un solo hilo: las tareas ceden en los puntos await, lo que escala a decenas de miles de sockets pero bloquea todo si llamas código síncrono dentro de una corrutina.
7
¿Qué es un context manager? ¿Cómo implementas el tuyo propio?
Respuesta
Un context manager garantiza setup y teardown alrededor de un bloque, que es lo que usan los statements with para cerrar archivos o liberar locks incluso cuando se lanza una excepción. Implementas uno ya sea como una clase con __enter__ y __exit__, o como un generador decorado con @contextlib.contextmanager que hace yield una vez entre el código de setup y el de limpieza. El método __exit__ recibe detalles de la excepción y puede suprimirla devolviendo True.
8
Explica MRO y herencia múltiple.
Respuesta
El Method Resolution Order define la secuencia en la que Python busca un atributo en las clases, calculada por el algoritmo de linearización C3. Garantiza que una clase siempre precede a sus padres y que el orden de las clases base se respeta, lo que hace predecible la herencia diamante. super() sigue el MRO en vez de saltar directo al padre, por eso la herencia múltiple cooperativa requiere que cada clase en la cadena llame a super().
9
¿Qué es el problema N+1 en Django ORM? ¿Cómo ayudan select_related y prefetch_related?
Respuesta
N+1 ocurre cuando un queryset devuelve N objetos y cada acceso a un campo relacionado dispara su propia consulta. select_related lo soluciona para ForeignKey y OneToOne haciendo un JOIN SQL y llenando el objeto relacionado en la misma consulta. prefetch_related maneja ManyToMany y relaciones inversas corriendo una segunda consulta y uniendo los resultados en Python, por eso produce dos consultas en vez de una.
10
¿Cuál es la diferencia entre una copia superficial y una copia profunda?
Respuesta
Una copia superficial crea un nuevo contenedor externo pero mantiene referencias a los mismos objetos anidados, así que mutar una lista anidada es visible a través de ambas copias. Una copia profunda duplica todo recursivamente, dando independencia completa al costo de tiempo y memoria. El bug que esto causa en la práctica es un argumento default mutable o una config anidada compartida que un caller muta para todos.
11
¿Cuál es la diferencia entre __str__ y __repr__?
Respuesta
__repr__ apunta a desarrolladores y debería idealmente ser inequívoco — a menudo algo que parece la expresión necesaria para recrear el objeto; es lo que muestran el REPL y los debuggers. __str__ apunta a usuarios finales y es lo que llaman print() y str(), recayendo en __repr__ cuando no está definido. Implementar __repr__ es el hábito de mayor valor porque hace los logs y tracebacks legibles.
12
¿Cómo gestiona Python la memoria y qué es el reference counting?
Respuesta
CPython libera un objeto tan pronto como su conteo de referencias llega a cero, lo que hace la desasignación inmediata y predecible. Como el conteo de referencias solo no puede liberar ciclos de referencias, un garbage collector cíclico generacional corre periódicamente para detectarlos y recolectarlos. Consecuencias prácticas: cerrar recursos explícitamente sigue siendo necesario, y mantener una referencia en un caché o un closure es la causa usual de una fuga de memoria.