Python Preguntas de entrevista
Las entrevistas de Python evalúan tu comprensión de las características principales del lenguaje, estructuras de datos, algoritmos y programación orientada a objetos. A menudo incluyen preguntas conceptuales para medir tu profundidad de conocimiento, además de problemas prácticos de codificación para evaluar habilidades prácticas. Ya seas desarrollador junior o senior, dominar estos temas es crucial para el éxito.
Lo que cubren las entrevistas de Python
Sintaxis básica y estructuras de datos
Preguntas sobre los tipos incorporados de Python como listas, diccionarios, conjuntos, tuplas y manipulación de cadenas, incluyendo complejidad temporal.
Programación Orientada a Objetos (POO)
Cubre clases, herencia, polimorfismo y métodos especiales como __init__, __str__ y decoradores de propiedades.
Programación funcional y comprensiones
Incluye lambda, map, filter, reduce, comprensiones de listas/diccionarios y expresiones generadoras.
Concurrencia y rendimiento
Temas como GIL, threading vs multiprocessing, async/await y profiling.
Ejemplos de preguntas de entrevista sobre Python
- ¿Cuáles son las características clave de Python?Lo que cubre una buena respuesta
- Python es interpretado y dinámicamente tipado.
- Soporta múltiples paradigmas: orientado a objetos, funcional, imperativo.
- Tiene una sintaxis clara y legible, enfatizando la legibilidad del código.
- Incluye una amplia biblioteca estándar y es extensible mediante módulos.
- Cuenta con gestión automática de memoria mediante recolección de basura.
Ver respuesta de ejemplo
Python es un lenguaje de alto nivel, interpretado y de tipado dinámico, lo que facilita el desarrollo rápido. Su sintaxis limpia y legible promueve buenas prácticas de programación. Soporta programación orientada a objetos, funcional y procedimental. La biblioteca estándar es muy completa, cubriendo desde manejo de archivos hasta servicios web. Además, Python tiene un amplio ecosistema de paquetes de terceros. Sin embargo, su naturaleza interpretada puede hacerlo más lento que lenguajes compilados. El tipado dinámico puede introducir errores en tiempo de ejecución. La gestión automática de memoria simplifica el desarrollo pero puede consumir más recursos. En general, Python es ideal para prototipado, ciencia de datos y automatización.
- Explica la diferencia entre lista y tupla. ¿Cuándo usarías cada una?Lo que cubre una buena respuesta
- Las listas son mutables; las tuplas son inmutables.
- Las listas se crean con corchetes []; las tuplas con paréntesis ().
- Las tuplas son más eficientes en memoria y velocidad que las listas.
- Las listas tienen métodos como append, extend, pop; las tuplas no.
- Las tuplas pueden usarse como claves de diccionario; las listas no.
Ver respuesta de ejemplo
La principal diferencia es que las listas son mutables (se pueden modificar después de creadas) mientras que las tuplas son inmutables. Esto implica que las listas tienen métodos para agregar, eliminar o modificar elementos, mientras que las tuplas no. Las tuplas son más ligeras en memoria y más rápidas al iterar, por lo que se recomiendan para datos que no cambiarán. Además, las tuplas pueden ser usadas como claves en diccionarios porque son hashables, a diferencia de las listas. Las listas son adecuadas para colecciones homogéneas de tamaño variable, mientras que las tuplas se usan para estructuras de datos fijas como coordenadas o registros. Un tradeoff es que la inmutabilidad de las tuplas puede ser una limitación si se necesita flexibilidad. En la práctica, si no se requiere modificar la colección, es preferible usar una tupla por eficiencia y seguridad.
- ¿Cómo gestiona Python la memoria? Discute la recolección de basura y el conteo de referencias.Lo que cubre una buena respuesta
- Python gestiona la memoria automáticamente mediante un administrador de memoria.
- Utiliza conteo de referencias como principal mecanismo de recolección de basura.
- También cuenta con un recolector de basura cíclico para detectar referencias circulares.
- Cada objeto tiene un contador de referencias que se incrementa/decrementa al crear/eliminar referencias.
- Cuando el contador llega a cero, el objeto es desalojado inmediatamente.
Ver respuesta de ejemplo
Python usa un sistema de gestión de memoria automático basado en conteo de referencias y un recolector de basura cíclico. Cada objeto en Python tiene un contador de referencias que se actualiza cuando se crean o eliminan referencias. Cuando el contador llega a cero, el objeto se libera de inmediato. Sin embargo, el conteo de referencias no maneja referencias circulares (por ejemplo, dos objetos que se apuntan mutuamente). Para eso, Python incluye un recolector de basura cíclico que periódicamente busca y elimina objetos inalcanzables formando ciclos. Este recolector se ejecuta de forma opcional y puede ser controlado mediante el módulo gc. La gestión automática simplifica el desarrollo pero puede introducir pausas y mayor consumo de memoria. Es importante entender que el recolector cíclico solo actúa sobre objetos contenedores (listas, diccionarios, etc.) y no sobre tipos simples.
- Escribe una función para encontrar el segundo número más grande en una lista sin usar ordenamiento.Lo que cubre una buena respuesta
- Recorrer la lista manteniendo dos variables: mayor y segundo mayor.
- Inicializar ambos como None o el primer elemento según corresponda.
- Actualizar adecuadamente al encontrar un valor mayor que el actual mayor.
- Considerar casos con elementos repetidos y listas con menos de dos elementos.
- Complejidad O(n) temporal y O(1) espacial.
Ver respuesta de ejemplo
La función recorre la lista una sola vez, manteniendo dos variables: primero y segundo mayor. Se inicializan como None y luego se actualizan conforme se encuentran valores mayores. Es crucial manejar correctamente el caso en que el nuevo valor es mayor que el primero: entonces el primero pasa a ser segundo y el nuevo valor se convierte en primero. También hay que considerar elementos iguales; si se permite empates, el segundo mayor puede ser igual al primero si hay al menos dos iguales. Se debe validar que la lista tenga al menos dos elementos. Este algoritmo tiene complejidad O(n) en tiempo y O(1) en espacio, mejor que ordenar que es O(n log n). Un pitfall común es no actualizar correctamente cuando el nuevo valor está entre el primero y el segundo.
Solución de referenciapython def segundo_mayor(lista): if len(lista) < 2: return None # Inicializar mayor y segundo como los dos primeros elementos if lista[0] > lista[1]: mayor, segundo = lista[0], lista[1] else: mayor, segundo = lista[1], lista[0] for num in lista[2:]: if num > mayor: segundo = mayor mayor = num elif num > segundo and num != mayor: # Considerar duplicados segundo = num return segundo # Complejidad temporal: O(n), espacial: O(1) - Implementa un decorador que mida el tiempo de ejecución de una función.Lo que cubre una buena respuesta
- Usar functools.wraps para preservar metadatos de la función original.
- La función decoradora toma una función como argumento y devuelve una envoltura.
- Dentro de la envoltura, registrar el tiempo antes y después de llamar a la función.
- Imprimir o retornar el tiempo transcurrido.
- Considerar el manejo de argumentos variables (*args, **kwargs).
Ver respuesta de ejemplo
Un decorador es una función que toma otra función y extiende su comportamiento sin modificar su código. Para medir tiempo, se usa time.perf_counter() para alta precisión. La envoltura debe aceptar cualquier número de argumentos y devolver el resultado de la función original. Usar functools.wraps copia el nombre y docstring de la función original a la envoltura, lo cual es buena práctica. El decorador puede imprimir el tiempo o almacenarlo en un atributo. Un pitfall es que si la función decorada es llamada muchas veces, se acumula tiempo de impresión. También es importante no interferir con excepciones: la envoltura debe propagar excepciones. La complejidad de la medición es O(1) adicional a la función.
Solución de referenciapython import time import functools def medir_tiempo(func): @functools.wraps(func) def envoltura(*args, **kwargs): inicio = time.perf_counter() resultado = func(*args, **kwargs) fin = time.perf_counter() print(f"{func.__name__} tardó {fin - inicio:.4f} segundos") return resultado return envoltura # Uso: @medir_tiempo def mi_funcion(): time.sleep(1) mi_funcion() - ¿Qué es el GIL? ¿Cómo afecta al multithreading?Lo que cubre una buena respuesta
- GIL significa Global Interpreter Lock (Bloqueo Global del Intérprete).
- Es un mutex que protege el acceso a objetos de Python, permitiendo solo un hilo a la vez.
- Afecta al multithreading porque los hilos no pueden ejecutarse en paralelo en CPU-bound tasks.
- Para tareas I/O-bound, el GIL se libera durante operaciones de E/S, por lo que multithreading puede ser beneficioso.
- Alternativas: multiprocessing para paralelismo real, o usar bibliotecas en C que liberen el GIL.
Ver respuesta de ejemplo
El GIL es un bloqueo global en el intérprete CPython que garantiza que solo un hilo ejecute bytecode de Python a la vez. Esto simplifica la gestión de memoria y evita condiciones de carrera en estructuras de datos internas. Sin embargo, limita el rendimiento de aplicaciones multithreading en tareas intensivas de CPU, ya que los hilos no pueden aprovechar múltiples núcleos. Para tareas de E/S (red, disco), el GIL se libera durante las operaciones de bloqueo, permitiendo que otros hilos avancen. Una alternativa es usar el módulo multiprocessing, que crea procesos independientes con su propio GIL, logrando paralelismo real. También se pueden usar bibliotecas como numpy que liberan el GIL en operaciones pesadas. Python 3 ha mejorado el GIL pero no lo ha eliminado. Es crucial comprender si el cuello de botella es CPU o I/O para elegir entre threads o procesos.
- Escribe un generador que produzca números de Fibonacci hasta n.Lo que cubre una buena respuesta
- Usar yield para producir cada número de Fibonacci hasta n.
- Mantener dos variables para los dos últimos números de la secuencia.
- Comenzar con 0 y 1 (o 1 y 1 según definición).
- El generador debe detenerse cuando el siguiente número excede n.
- Es eficiente en memoria porque produce valores sobre la marcha.
Ver respuesta de ejemplo
Un generador es una función que usa la sentencia yield para devolver valores uno a uno, manteniendo su estado entre llamadas. Para Fibonacci, se inicializan a y b como los primeros dos números. En cada iteración, se produce a y se actualizan a=b, b=a+b. Se debe incluir una condición para detenerse cuando a > n. Es importante decidir si incluir el 0 y si n es el límite superior inclusive. La ventaja del generador es que no almacena toda la secuencia en memoria, ideal para secuencias grandes. Un pitfall es que si n es muy pequeño, puede no producir nada. También se puede usar una versión recursiva, pero no es eficiente. Complejidad O(n) en tiempo, O(1) en espacio.
Solución de referenciapython def fibonacci_hasta_n(n): a, b = 0, 1 while a <= n: yield a a, b = b, a + b # Uso: for num in fibonacci_hasta_n(100): print(num) - Explica el MRO (Orden de Resolución de Métodos) en Python y cómo funciona super().Lo que cubre una buena respuesta
- MRO (Method Resolution Order) define el orden en que se buscan los métodos en una jerarquía de herencia.
- Python usa el algoritmo C3 linearization para calcular el MRO.
- Se puede consultar mediante __mro__ o mro().
- super() permite llamar a métodos de la clase padre siguiendo el MRO.
- Es esencial para la herencia múltiple para evitar llamadas repetidas y garantizar el orden correcto.
Ver respuesta de ejemplo
El MRO es el orden en que Python busca métodos en las clases base. Para herencia simple, es lineal; para herencia múltiple, usa el algoritmo C3 que garantiza consistencia y monotonicidad. La función super() devuelve un objeto proxy que delega las llamadas de método a la siguiente clase en el MRO. Esto es crucial para cooperación en herencia múltiple, ya que evita llamar al mismo método varias veces (problema del diamante). Por ejemplo, si varias clases heredan de una misma base, super() asegura que el método de la base se llame una sola vez. Un error común es pensar que super() siempre llama al padre directo; en realidad sigue el MRO dinámico. Es importante usar super() con la firma correcta y en todas las clases cooperantes. El MRO se puede inspeccionar con ClassName.__mro__. El entendimiento del MRO es fundamental para diseñar jerarquías de herencia complejas sin efectos laterales.
Cómo prepararse
- Domina las funciones incorporadas y la biblioteca estándar (por ejemplo, itertools, collections).
- Practica problemas de codificación en plataformas como LeetCode o HackerRank con enfoque en soluciones específicas de Python.
- Comprende el modelo de memoria de Python y cómo se pasan los objetos (referencia vs valor).
- Sé capaz de explicar patrones de diseño y modismos Pythonicos (por ejemplo, administradores de contexto, decoradores).
- Revisa estructuras de datos importantes: diccionarios, conjuntos y sus complejidades temporales.
Preguntas frecuentes
¿Cuál es la diferencia entre `==` y `is`?
`==` verifica igualdad de valor; `is` verifica identidad (mismo objeto). Usa `is` para singletons como None.
¿Cómo manejas las excepciones en Python?
Usa bloques try/except; opcionalmente con else y finally para limpieza. Evita excepts desnudos.
¿Qué son los espacios de nombres y las reglas de ámbito en Python?
Regla LEGB: Local, Enclosing, Global, Built-in. Las variables se buscan en ese orden.
¿Qué es un generador y en qué se diferencia de una lista?
Los generadores producen elementos de forma perezosa usando yield; no almacenan todos los valores en memoria, adecuados para datos grandes.
¿Cómo optimizas el código Python para el rendimiento?
Usa funciones incorporadas (por ejemplo, map, filter), comprensiones de listas, evita búsquedas globales, usa herramientas de profiling y considera extensiones en C.
Practica preguntas sobre Python con retroalimentación instantánea de IA
Sube tu currículum, obtén una entrevista simulada personalizada y ve exactamente qué mejorar — gratis para empezar.