Módulos#

Importando módulos#

  • Las definiciones de funciones en Python en uno o más archivos separados para facilitar su manteniniento y para permitir usarlos en varios programas sin copiar las definiciones en cada uno.

  • Cada archivo que almacenda definciones de funciones se llama “módulo” y el nombre del módulo es igual al del archivo pero sin la extensión “.py”.

  • Las funciones almacenadas en un módulo están disponibles para un programa usando la palabra clave import seguida del nombre del módulo.

  • Aunque no es esencial, se acostumbra poner las instrucciones import al inicio del programa.

  • Las funciones importadas pueden usarse llamando su nombre como un “punto-sufijo” luego del nombre del módulo. Por ejemplo, una función sqrt de un módulo importado numpy puede llamarse con numpy.sqrt()

Algunos paquetes (módulos) muy útiles#

En nuestro curso, los siguientes paquetes (= colecciones de módulos) serán muy útiles

  • numpy Paquete base para arreglos N-dimensional. Operaciones matemáticas, especialmente álgebra lineal

  • matplotlib gráficos 2D

  • pandas estructuras para almacenar y analizar datos

  • scipy librería fundamental para computación científica

  • bccr ofrece funciones para descargar datos del Banco Central de Costa Rica

  • macrodemos contiene demos de conceptos macroeconométricos, por ejemplo los modelos ARMA

  • compecon Para resolver modelos de economía computacional

Algunos ejemplos:#

Para importar numpy

import numpy
numpy.sqrt(9)
3.0

Mismo ejemplo, pero dándolo un “alias” al módulo

import numpy as np
np.sqrt(9)
3.0

Mismo ejemplo, pero importando solo la función sqrt

from numpy import sqrt, cos, sin
sqrt(9)
3.0

¿Por qué trabajar con módulos?#

  • Una ventaja de organizar el código en módulos y paquetes es evitar desordenar el espacio de nombres.

  • Los módulos permites tener funciones del mismo nombre en espacios de nombre separados, obligándonos a ser explícitos acerca de cuál es la que usamos.

Por ejemplo, tanto math como numpy tienen una función cos para computar el coseno, pero su implementación es muy distinta.

Con numpy:#

\(\pi\)

π = np.pi
np.cos(π)
-1.0
import numpy as np
print(np.cos(0))
print(np.cos([0,   1,   np.pi]))
1.0
[ 1.          0.54030231 -1.        ]

Con math:#

Esta celda da un error, porque la función math.cos fue definida para calcular el coseno de un único número, no de una lista de números a la vez (como sí lo hace la función np.cos)

import math
print(math.cos(0))
print(math.cos([0,1, np.pi]))
1.0
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_1036/1563810609.py in <module>
      1 import math
      2 print(math.cos(0))
----> 3 print(math.cos([0,1, np.pi]))

TypeError: must be real number, not list

Iteración más rápida#

nrep = 12_000
values = list(range(nrep))
%%timeit
option0 = np.empty_like(values)

for i, x in enumerate(values):
    option0[i] = math.cos(x)
4.53 ms ± 59.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
option1 = list()
for x in values:
    option1.append(math.cos(x))
2.4 ms ± 25.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
option2 = [math.cos(x) for x in values]
1.85 ms ± 19.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
option3 = np.cos(values)
954 µs ± 8.72 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Ejemplo de módulo: Trabajando con decimales#

Los programas de cómputo que ejecutan aritmética con números de punto flotante pueden producir resultados inesperados e imprecisos porque los números de punto flotante no pueden representar adecuadamente todos los número decimales.

item, rate = 0.70, 1.05
tax = item * rate
total = item + tax
txt, val = ['item','tax','total'], [item,tax,total]

for tt, vv in zip(txt, val):
    print(f'{tt:5s} = {vv:.2f}')
item  = 0.70
tax   = 0.73
total = 1.44

Con más decimales

for tt, vv in zip(txt, val):
    print(f'{tt:8s} = {vv:.20f}')
item     = 0.69999999999999995559
tax      = 0.73499999999999998668
total    = 1.43500000000000005329

Los errores de la aritmética de punto flotante pueden evitarse usando el módulo de Python decimal. Este módulo contiene un objeto Decimal() con el cual los números de punto flotante pueden representarse con más precisión.

from decimal import Decimal
item, rate = Decimal('0.70'), Decimal('1.05')
tax = item * rate
total = item + tax

txt, val = ['item','tax','total'], [item,tax,total]

for tt, vv in zip(txt, val):
    print(f'{tt:5s} = {vv:.2f}')
item  = 0.70
tax   = 0.74
total = 1.44

Con más decimales

for tt, vv in zip(txt, val):
    print(f'{tt:5s} = {vv:.20f}')
item  = 0.70000000000000000000
tax   = 0.73500000000000000000
total = 1.43500000000000000000

Creando un módulo#

Los módulo son muy convenientes para almacenar funciones relacionadas en un solo archivo, de manera que podamos mantener el orden en nuestro proyecto y además reutilizar esas funciones en distintos lugares.

Por ejemplo, archivo módulo_sencillo.py que está en la misma carpeta que este cuaderno de Jupyter contiene una función llamada hola, con la saludamos. Además, hay una variable “string” llamada fecha, donde guardé la fecha en que hice este módulo.

from módulo_sencillo import hola, fecha

Para crear un módulo, simplemente almacenamos una o más definiciones (de funciones, variables, clases) en un archivo con extensión .py. Si el archivo está en la misma carpeta que el archivo de Python en ejecución, lo podemos importar directamente.

hola()
Hola!! Soy la función `hola` del módulo `módulo_sencillo`
No hago más que saludar
fecha
'27 de marzo de 2022'

Otra manera es cargar el módulo completo, en cuyo caso

import módulo_sencillo
módulo_sencillo.hola()
Hola!! Soy la función `hola` del módulo `módulo_sencillo`
No hago más que saludar
módulo_sencillo.fecha
'27 de marzo de 2022'

Como no es práctico escribir módulo_sencillo cada vez que usamos una de sus definiciones, le podemos poner un nombre más corto al importarlo, por ejemplo

import módulo_sencillo as ms

ms.hola()
Hola!! Soy la función `hola` del módulo `módulo_sencillo`
No hago más que saludar
ms.fecha
'27 de marzo de 2022'