Link Search Menu Expand Document

M贸dulos en Python

Introducci贸n

Un m贸dulo o module en Python es un fichero .py que alberga un conjunto de funciones, variables o clases y que puede ser usado por otros m贸dulos. Nos permiten reutilizar c贸digo y organizarlo mejor en namespaces. Por ejemplo, podemos definir un m贸dulo mimodulo.py con dos funciones suma() y resta().

# mimodulo.py
def suma(a, b):
    return a + b

def resta(a, b):
    return a - b

Una vez definido, dicho m贸dulo puede ser usado o importado en otro fichero, como mostramos a continuaci贸n. Usando import podemos importar todo el contenido.

# otromodulo.py
import mimodulo

print(mimodulo.suma(4, 3))   # 7
print(mimodulo.resta(10, 9)) # 1

Tambi茅n podemos importar 煤nicamente los componentes que nos interesen como mostramos a continuaci贸n.

from mimodulo import suma, resta

print(suma(4, 3))   # 7
print(resta(10, 9)) # 1

Por 煤ltimo, podemos importar todo el m贸dulo haciendo uso de *, sin necesidad de usar mimodulo.*.

from mimodulo import *

print(suma(4, 3))   # 7
print(resta(10, 9)) # 1

Rutas y Uso de sys.path

Normalmente los m贸dulos que importamos est谩n en la misma carpeta, pero es posible acceder tambi茅n a m贸dulos ubicados en una subcarpeta. Imaginemos la siguiente estructura:

.
鈹溾攢鈹 ejemplo.py
鈹溾攢鈹 carpeta
鈹   鈹斺攢鈹 modulo.py

Donde modulo.py contiene lo siguiente:

# modulo.py
def hola():
	print("Hola")

Desde nuestro ejemplo.py, podemos importar el m贸dulo modulo.py de la siguiente manera:

from carpeta.modulo import *
print(hola())
# Hola

Es importante notar que Python busca los m贸dulos en las rutas indicadas por el sys.path. Es decir, cuando se importa un m贸dulo, lo intenta buscar en dichas carpetas. Puedes ver tu sys.path de la siguiente manera:

import sys
print(sys.path)

Como es obvio, ver谩s que la carpeta de tu proyecta est谩 incluida, pero 驴y si queremos importar un m贸dulo en una ubicaci贸n distinta? Pues bien, podemos a帽adir al sys.path la ruta en la que queremos que Python busque.

import sys
sys.path.append(r'/ruta/de/tu/modulo')

Una vez realizado esto, los m贸dulos contenidos en dicha carpeta podr谩n ser importados sin problema como hemos visto anteriormente.

Cambiando los Nombres con as

Por otro lado, es posible cambiar el nombre del m贸dulo usando as. Imaginemos que tenemos un m贸dulo moduloconnombrelargo.py.

# moduloconnombrelargo.py
hola = "hola"

En vez de usar el siguiente import, tal vez queramos asignar un nombre m谩s corto al m贸dulo.

import moduloconnombrelargo
print(moduloconnombrelargo.hola)

Podemos hacerlo de la siguiente manera con as:

import moduloconnombrelargo as m
print(m.hola)

##聽Listando dir

La funci贸n dir() nos permite ver los nombres (variables, funciones, clases, etc) existentes en nuestro namespace. Si probamos en un m贸dulo vac铆o, podemos ver como tenemos varios nombres rodeados de __. Se trata de nombres que Python crea por debajo.

print(dir())
# ['__annotations__', '__builtins__', '__cached__', '__doc__',
# '__file__', '__loader__', '__name__', '__package__', '__spec__']

Por ejemplo, __file__ es creado autom谩ticamente y alberga el nombre del fichero .py.

print(__file__)
#/tu/ruta/tufichero.py

Imaginemos ahora que tenemos alguna variable y funci贸n definida en nuestro script. Como era de esperar, dir() ahora nos muestra tambi茅n los nuevos nombres que hemos creado, y que por supuesto pueden ser usados.

mi_variable = "Python"
def mi_funcion():
    pass

print(dir())

#['__annotations__', '__builtins__', '__cached__', '__doc__',
# '__file__', '__loader__', '__name__', '__package__', '__spec__',
# 'mi_funcion', 'mi_variable']

Por 煤ltimo, vamos a importar el contenido de un m贸dulo externo. Podemos ver que en el namespace tenemos tambi茅n los nombres resta y suma, que han sido tomados de mimodulo.

from mimodulo import *
print(dir())

# ['__annotations__', '__builtins__', '__cached__',
# '__doc__', '__file__', '__loader__', '__name__',
# '__package__', '__spec__', 'resta', 'suma']

El uso de dir() tambi茅n acepta par谩metros de entrada, por lo que podemos por ejemplo pasar nuestro modulo y nos dar谩 m谩s informaci贸n sobre lo que contiene.

import mimodulo

print(dir(mimodulo))
# ['__builtins__', '__cached__', '__doc__',
# '__file__','__loader__', '__name__',
# '__package__', '__spec__', 'resta', 'suma']

print(mimodulo.__name__)
# mimodulo

print(mimodulo.__file__)
# /tu/ruta/mimodulo.py

Excepci贸n ImportError

Importar un m贸dulo puede lanzar una excepci贸n, cuando se intenta importar un m贸dulo que no ha sido encontrado. Se trata de ModuleNotFoundError.

import moduloquenoexiste
# ModuleNotFoundError: No module named 'moduloquenoexiste'

Dicha excepci贸n puede ser capturada para evitar la interrupci贸n del programa.

try:
    import moduloquenoexiste
except ModuleNotFoundError as e:
    print("Hubo un error:", e)

M贸dulos y Funci贸n Main

Un problema muy recurrente es cuando creamos un m贸dulo con una funci贸n como en el siguiente ejemplo, y a帽adimos algunas sentencias a ejecutar.

# modulo.py

def suma(a, b):
    return a + b

c = suma(1, 2)
print("La suma es:", c)

Si en otro m贸dulo importamos nuestro modulo.py, tal como est谩 nuestro c贸digo el contenido se ejecutar谩, y esto puede no ser lo que queramos.

# otromodulo.py
import modulo

# Salida: La suma es: 3

Dependiendo de la situaci贸n, puede ser importante especificar que 煤nicamente queremos que se ejecute el c贸digo si el m贸dulo es el __main__. Con la siguiente modificaci贸n, si hacemos import modulo desde otro m贸dulo, este fragmento ya no se ejecutar谩 al ser el m贸dulo main otro.

# modulo.py
def suma(a, b):
    return a + b

if (__name__ == '__main__'):
    c = suma(1, 2)
    print("La suma es:", c)

Recargando M贸dulos

Es importante notar que los m贸dulos solamente son cargados una vez. Es decir, no importa el n煤mero de veces que llamemos a import mimodulo, que s贸lo se importar谩 una vez.

Imaginemos que tenemos el siguiente m贸dulo que imprime el siguiente contenido cuando es importado.

#聽mimodulo.py

print("Importando mimodulo")

def suma(a, b):
    return a + b

def resta(a, b):
    return a - b

A pesar de que llamamos tres veces al import, s贸lo vemos una 煤nica vez el contenido del print.

import mimodulo
import mimodulo
import mimodulo
# Importando mimodulo

Si queremos que el m贸dulo sea recargado, tenemos que ser expl铆citos, haciendo uso de reload.

import mimodulo
import importlib
importlib.reload(mimodulo)
importlib.reload(mimodulo)