Módulos

A lo largo de nuestro aprendizaje de Python, hemos estado utilizando funciones predefinidas como print(), input(), type(), etc. Python tiene una gran cantidad de funciones, y no todas son accesibles directamente desde un nuevo script de Python. En su lugar, están almacenadas en archivos separados llamados módulos. Para utilizar estas funciones, necesitamos importar el módulo que las contiene. Esto se hace utilizando la instrucción import. Ilustremos esto:
import math           # Importando el módulo math

print(math.pi)        # Accediendo a la constante pi del módulo math
print(math.sqrt(16))  # Accediendo a la función raíz cuadrada del módulo math
Este programa imprimirá el valor de pi (3.141592653589793) y la raíz cuadrada de 16 (4.0).
También podemos importar atributos o funciones específicos de un módulo utilizando la instrucción from...import:
from math import pi, sqrt  # Importando solo pi y sqrt del módulo math

print(pi)                  # Podemos usar pi directamente sin anteponer el nombre del módulo
print(sqrt(16))            # De manera similar, podemos usar sqrt directamente
La salida del programa será la misma que la anterior.
A veces, los módulos tienen nombres largos, y escribir el nombre completo cada vez que queremos usar una función puede ser laborioso. Para evitar esto, podemos usar la palabra clave as para asignar un nombre diferente (alias) al módulo.
import math as m   # Importando el módulo math y renombrándolo como m

print(m.pi)        # Ahora podemos usar el alias corto
print(m.sqrt(16))  # Usando la función sqrt mediante el alias
La salida también será 3.141592653589793 y 4.0, igual que antes.
En conclusión, los módulos en Python son como cajas de herramientas que contienen funciones y variables predefinidas que podemos importar y usar en nuestros programas. Ayudan a organizar el código y hacerlo más eficiente.
Cómo funcionan los módulos internamente
Cuando importas un módulo, Python realiza algunas operaciones detrás de escena que podrían no ser inmediatamente evidentes. Aquí hay una visión general de lo que sucede cuando usas la instrucción import:
  1. Localización del módulo: Python primero busca el módulo comprobando las ubicaciones especificadas en su lista sys.path. Esta lista incluye el directorio actual, el directorio de paquetes integrados de Python y cualquier ruta especificada en la variable de entorno PYTHONPATH. Si Python encuentra el módulo, procede a los siguientes pasos. Si no, lanza un ModuleNotFoundError.
  1. Inicialización del módulo: Una vez que se localiza el archivo del módulo, Python crea un nuevo objeto módulo (types.ModuleType). Entonces carga el contenido del módulo en este nuevo objeto, ejecutando todo el código de nivel superior en el archivo del módulo. Esto incluye definiciones de funciones, clases, variables y la ejecución de código de inicialización.
  1. Almacenamiento en caché del módulo: Después de la inicialización, el módulo se almacena en caché en sys.modules (un diccionario). Este paso garantiza que cuando el mismo módulo se importe nuevamente en el script (o por otros scripts), Python no necesite localizar e inicializar el módulo otra vez. En su lugar, puede usar la versión en caché. La clave en este diccionario es el nombre del módulo, y el valor es el objeto módulo.
  1. Agregando el módulo al espacio de nombres del importador: Finalmente, Python añade el nombre del módulo al espacio de nombres del script o módulo que lo importó. El nombre se refiere al objeto módulo, por lo que puedes acceder a las funciones y variables del módulo usando la notación de punto.
Vamos a ilustrar esto con algo de código:
import sys
import math

print(sys.path)       # La ruta donde Python busca los módulos
print(sys.modules)    # Los módulos en caché
print(math.sqrt(16))  # Accediendo a una función del módulo math
sys.path imprime una lista de directorios donde Python busca módulos. sys.modules imprime un diccionario de nombres de módulos (claves) y sus respectivos objetos módulo (valores).

Desafío: Números Aleatorios

En el mundo de la criptografía, los números aleatorios desempeñan un papel increíblemente crucial. Los algoritmos criptográficos a menudo dependen de generar una secuencia de números aleatorios para mantener los datos seguros.
En este desafío, se te asigna la tarea de simular un generador simple de números aleatorios que nos ayudará a entender la aleatoriedad de una forma más tangible. Python viene con un módulo incorporado llamado random que tiene varias funciones para generar números aleatorios. Se te pide que uses este módulo para generar una lista de n enteros aleatorios entre dos números dados a y b. Sin embargo, la aleatoriedad no debe ser verdaderamente aleatoria; necesitamos fijar la semilla en 42 para la repetibilidad del experimento. Puedes usar la función seed() para fijar la semilla y randint() para generar un número aleatorio.
La primera línea de la entrada contiene tres enteros separados por espacios: n, a y b. Los números a y b determinan el rango (inclusivo) del cual se deben seleccionar los números aleatorios, y n determina cuántos de esos números necesitas generar.
El programa debe imprimir n números aleatorios separados por espacios generados dentro del rango [a, b] con la semilla aleatoria fijada en 42.
Entrada
Salida
10 1 100
82 15 4 95 36 32 29 18 95 14
5 1 5
1 1 3 2 2
3 10 20
20 11 10
Nota: Al establecer la semilla aleatoria en 42, la secuencia de salida debe permanecer igual en múltiples ejecuciones del programa. Esta es una característica que aprovechamos en pruebas, depuración y otros escenarios donde es necesario un resultado determinístico.
 

Constraints

Time limit: 2 seconds

Memory limit: 512 MB

Output limit: 1 MB

To check your solution you need to sign in
Sign in to continue