Python Intermedio: Estructuras de Datos, Funciones y OOP
Explica la diferencia entre una lista (list) y una tupla (tuple) en Python.
Respuesta:
Las listas son mutables, lo que significa que sus elementos pueden ser modificados después de su creación, y se definen usando corchetes []. Las tuplas son inmutables, lo que significa que sus elementos no pueden ser modificados, y se definen usando paréntesis (). Las tuplas son generalmente más rápidas y pueden usarse como claves de diccionario.
¿Qué es una comprensión de diccionario (dictionary comprehension)? Proporciona un ejemplo.
Respuesta:
Una comprensión de diccionario es una forma concisa de crear diccionarios. Consiste en una expresión seguida de una cláusula for, luego cero o más cláusulas for o if. Por ejemplo: squares = {x: x*x for x in range(5)} crea {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}.
¿Cuál es el propósito de *args y **kwargs en las definiciones de funciones?
Respuesta:
*args permite que una función acepte un número arbitrario de argumentos posicionales, que se recopilan en una tupla. **kwargs permite que una función acepte un número arbitrario de argumentos de palabra clave, que se recopilan en un diccionario. Permiten firmas de función flexibles.
Explica el concepto de decorador (decorator) en Python.
Respuesta:
Un decorador es un patrón de diseño que te permite modificar o extender la funcionalidad de una función o método sin cambiar explícitamente su código fuente. Es esencialmente una función que toma otra función como argumento, añade alguna funcionalidad y devuelve una nueva función. Se utilizan comúnmente para logging, medición de tiempo o control de acceso.
¿Cuál es la diferencia entre los métodos __init__ y __new__ en las clases de Python?
Respuesta:
__new__ es un método estático responsable de crear y devolver una nueva instancia de la clase antes de que se llame a __init__. __init__ es un método de instancia que inicializa el objeto recién creado. __new__ rara vez se sobrescribe a menos que necesites controlar la creación del objeto en sí, como en el caso de los singletons.
Describe la sobrescritura de métodos (method overriding) y la sobrecarga de métodos (method overloading) en Python.
Respuesta:
La sobrescritura de métodos ocurre cuando una subclase proporciona una implementación específica para un método que ya está definido en su superclase. Python no soporta la sobrecarga de métodos tradicional (múltiples métodos con el mismo nombre pero diferentes parámetros) directamente; en su lugar, puedes usar argumentos por defecto o *args/**kwargs para lograr una flexibilidad similar.
¿Qué es un generador (generator) en Python y por qué lo usarías?
Respuesta:
Un generador es una función que devuelve un iterador que produce una secuencia de resultados uno a la vez usando la palabra clave yield, en lugar de devolver un único valor. Son eficientes en cuanto a memoria porque no almacenan toda la secuencia en memoria, lo que los hace ideales para grandes conjuntos de datos o secuencias infinitas.
Explica el Global Interpreter Lock (GIL) en Python.
Respuesta:
El GIL es un mutex que protege el acceso a los objetos de Python, impidiendo que múltiples hilos nativos ejecuten bytecode de Python a la vez. Esto significa que, incluso en procesadores multinúcleo, solo un hilo puede ejecutar bytecode de Python en un momento dado. Simplifica la gestión de memoria pero puede limitar la ejecución paralela real para tareas ligadas a la CPU.
¿Cuál es el propósito de super() en Python?
Respuesta:
super() se utiliza para llamar a un método de una clase padre o hermana. Permite acceder a métodos heredados que han sido sobrescritos en una subclase, asegurando el orden de resolución de métodos (MRO) adecuado en jerarquías de herencia complejas. Se usa comúnmente en los métodos __init__ de las subclases.
¿Cómo se manejan las excepciones (exceptions) en Python? Proporciona un ejemplo básico.
Respuesta:
Las excepciones se manejan usando bloques try, except, else y finally. El bloque try contiene código que podría generar una excepción. except captura excepciones específicas. else se ejecuta si no ocurre ninguna excepción, y finally se ejecuta siempre, independientemente de si ocurrió una excepción. Ejemplo: try: 1/0 except ZeroDivisionError: print('Cannot divide by zero').
¿Cuál es la diferencia entre copia superficial (shallow copy) y copia profunda (deep copy)?
Respuesta:
Una copia superficial crea un nuevo objeto compuesto pero luego inserta referencias a los objetos encontrados en el original. Si el original contiene objetos mutables, los cambios en esos objetos se reflejarán en la copia superficial. Una copia profunda crea un nuevo objeto compuesto y luego inserta recursivamente copias de los objetos encontrados en el original, asegurando una independencia completa.
Explica el concepto de gestores de contexto (context managers) y la sentencia with.
Respuesta:
Los gestores de contexto proporcionan una forma limpia de gestionar recursos, asegurando que las operaciones de configuración y limpieza se manejen correctamente, incluso si ocurren errores. La sentencia with se utiliza para gestionar automáticamente la adquisición y liberación de recursos. Usos comunes incluyen el manejo de archivos, conexiones a bases de datos y bloqueos, asegurando que los recursos se cierren correctamente.