¿Cómo se crea un paquete?

Cuando creamos aplicaciones relativamente grandes, es normal llegar a tener muchos módulos; muchos de ellos estarán relacionados. Entonces, esos módulos relacionados, pueden formar parte de paquetes, con el fin de crear agrupaciones de módulos.
Los paquetes en Python, son muy fáciles de crear y permiten generar una estructura jerárquica. Tan solo deberás hacer una carpeta y guardar módulos en ella.

En la imagen puedes apreciar un ejemplo de paquete. Es una simple carpeta, que contiene archivos de Python.
En este paquete llamado paquete
, tenemos dos
módulos, aunque pueden ser todos los que quieras.
Espacio publicitario
Con el fin de que empieces a practicar y a ver de qué forma funcionan estos paquetes, crea la estructura planteada en la imagen, y añade el código que te expongo a continuación.
Para el modulo1.py tienes el siguiente código:
modulo1.pydef descripcion():
print("Soy el módulo 1.")
Para el modulo2.py tienes el siguiente código:
modulo2.pydef descripcion():
print("Soy el módulo 2.")
Cuando trabajes con módulos, acuérdate de guardar siempre los cambios, antes de intentar utilizarlos desde otro archivo.
Para importar
modulo1.py en el
módulo modulo2.py, solo tienes que utilizar un import
:
import modulo1
def descripcion():
print("Soy el módulo 2.")
# Llamo a la función del módulo importado
modulo1.descripcion()
Soy el módulo 1.
Ahora que está claro el acceso de elementos entre módulos de un paquete, vamos a hacer importaciones externas al paquete. Es decir, vamos a importar los módulos del paquete desde un módulo externo.
Paquete en inglés se traduce como package.
Espacio publicitario
Importar los módulos de un paquete
Para que veas de qué forma funciona el acceso de paquetes y módulos, vamos a crear finalmente la estructura que ves en la imagen:

Por un lado, contamos con la carpeta del proyecto. La que tienes abierta en tu IDE o editor de código.
Dentro del proyecto nos encontramos con el paquete y un archivo llamado principal.py. Desde este, vamos a intentar acceder a los módulos del paquete.
Finalmente, dentro del paquete, tenemos los dos módulos.
Para la prueba de acceso, voy a llamar desde principal.py, a las dos funciones que lleva cada uno de los módulos.
Este es el código de cada archivo:
modulo1.pydef descripcion():
print("Soy el módulo 1.")
modulo2.py
def descripcion():
print("Soy el módulo 2.")
principal.py
import paquete.modulo1, paquete.modulo2
paquete.modulo1.descripcion()
paquete.modulo2.descripcion()
Soy el módulo 1.
Soy el módulo 2.
¡Excelente! Ha funcionado ¿Has visto qué fácil?
La sintaxis de importación del paquete es esta:
paquete.modulo
Es como una ruta a una carpeta, donde tenemos carpeta/archivo.
Si algo no te funciona, revisa que tengas los nombres del paquete y módulos escritos correctamente, y que cada archivo está en su correspondiente lugar.
Espacio publicitario
Importar un solo elemento de un módulo, que pertenece a un paquete
Lo siguiente que vamos a hacer, será añadir una función más a modulo1.py:
modulo1.pydef descripcion():
print("Soy el módulo 1.")
def suma(a, b):
return a + b
Desde principal.py,
vamos a importar solo la función suma()
de
modulo1.py:
# Importa solo la función suma()
from paquete.modulo1 import suma
# Utilizamos la función
operacion = suma(10, 30)
# Imprimimos el resultado
print(operacion)
40
Paquetes y alias
En el código visto anteriormente, podemos apreciar que al utilizar paquetes nos queda un acceso demasiado largo a los elementos.
Por ejemplo:
principal.pyimport paquete.modulo1, paquete.modulo2
paquete.modulo1.descripcion()
paquete.modulo2.descripcion()
Puedes hacer uso de alias para facilitar el acceso:
principal.pyimport paquete.modulo1 as md1
import paquete.modulo2 as md2
md1.descripcion()
md2.descripcion()
Soy el módulo 1.
Soy el módulo 2.
Espacio publicitario
Subpaquetes
Denominamos subpaquetes a aquellos paquetes que están dentro de otros paquetes.
En la imagen puedes apreciar como el subpaquete, está dentro del paquete.

Para acceder a los módulos del subpaquete, la sintaxis es la siguiente:
paquete.subpaquete.modulo
Hagamos una prueba. Crea la estructura que ves en la imagen.
Crea el subpaquete dentro del paquete y añade los módulos modulo3.py y modulo4.py.
Añádeles este código:
modulo3.pydef descripcion():
print("Soy el módulo 3.")
modulo4.py
def descripcion():
print("Soy el módulo 4.")
Ahora, vamos a probar de acceder a cada función, desde el archivo principal.py:
principal.pyimport paquete.subpaquete.modulo3
import paquete.subpaquete.modulo4
paquete.subpaquete.modulo3.descripcion()
paquete.subpaquete.modulo4.descripcion()
Soy el módulo 3.
Soy el módulo 4.
Una vez más, hemos podido acceder. Sin embargo, las llamadas a los módulos quedan muy largas. Para utilizar un alias con estos subpaquetes, puedes hacerlo así:
principal.pyimport paquete.subpaquete.modulo3 as md3
import paquete.subpaquete.modulo4 as md4
md3.descripcion()
md4.descripcion()
Espacio publicitario
Importar un paquete
En Python, se nos permite importar un paquete entero, en lugar de módulos sueltos, como has visto en los ejemplos anteriores.
La sintaxis es esta:
import nombre_paquete
Sin embargo, si intentas utilizar algo del paquete, no te va a funcionar, así que es bastante inútil.
Aquí tienes un ejemplo:
import paquete
paquete.modulo1.descripcion()
AttributeError: module 'paquete' has no attribute 'modulo1'
Error de atributo: el módulo 'paquete' no tiene el atributo 'modulo1'
Por el error, podemos ver que está intentando tratar al paquete como si fuera un módulo, y el módulo como un atributo de este. Por eso recibimos el error de atributo inexistente.
Archivo __init__.py
Para inicializar paquetes enteros, podemos crear un archivo especial llamado __init__.py. Gracias a este archivo conseguiremos inicializar los datos a nivel de paquete.
Fíjate en la siguiente imagen. Añade este archivo inicializador al paquete. Sigue con la estructura que llevas hasta ahora, pero añade ese archivo. Solo eso.

En el archivo __init__.py vamos a escribir el siguiente código:
__init__.pyprint(f"El paquete llamado '{__name__}' ha sido inicializado.")
Al ejecutar el archivo principal.py con la importación del paquete, veremos que la inicialización se hace correctamente:
import paquete
El paquete llamado 'paquete' ha sido inicializado.
Vamos a probar si podemos acceder a elementos a nivel de paquete.
Añade una sencilla función al archivo __init__.py:
__init__.pyprint(f"El paquete llamado '{__name__}' ha sido inicializado.")
def descripcion():
print("Soy el paquete.")
Lo siguiente, será intentar acceder a esta función desde el archivo principal.py; lo podemos hacer de la siguiente forma:
principal.pyimport paquete as pqt
pqt.descripcion()
El paquete llamado 'paquete' ha sido inicializado.
Soy el paquete.
Espacio publicitario
¡Bien! Ha funcionado.
Ahora podrías pensar que poniendo un punto al nombre del paquete, podrás acceder a los diferentes módulos que tiene.
Probémoslo con el siguiente código en principal.py:
principal.pyimport paquete as pqt
pqt.modulo1.descripcion()
AttributeError: module 'paquete' has no attribute 'modulo1'
Error de atributo: el módulo 'paquete' no tiene el atributo 'modulo1'
No funciona.
La solución es sencilla. Importa los módulos del paquete en su archivo __init__.py, que le da una inicialización. Así, con la importación lo podremos inicializar todo:
__init__.pyimport paquete.modulo1, paquete.modulo2
print(f"El paquete llamado '{__name__}' ha sido inicializado.")
def descripcion():
print("Soy el paquete.")
Después de guardar los cambios, prueba de ejecutar principal.py:
import paquete as pqt
pqt.modulo1.descripcion()
El paquete llamado 'paquete' ha sido inicializado.
Soy el módulo 1.
La variable especial __name__
Te habrás fijado que en el módulo de inicialización del
paquete, en el print()
, he utilizado una
variable especial llamada __name__
. Esta
variable establece el valor __main__
si se
ejecuta con el archivo que la contiene.
El término name se traduce como nombre en español. El término main, se traduce como principal.
Ejecuta el archivo __init__.py con este código (borra todo el código de los ejemplos anteriores y deja solo esto):
__init__.pyprint(f"El paquete llamado '{__name__}' ha sido inicializado.")
El paquete llamado '__main__' ha sido inicializado.
Si esta variable es ejecutada desde el propio archivo que
la contiene, su valor es __main__
.
En cambio, si esta variable se ejecuta desde otro archivo, como hemos hecho anteriormente, nos da el nombre del archivo en donde está escrita:
Ejecutamos principal.py con este código:
principal.pyimport paquete
El paquete llamado 'paquete' ha sido inicializado.
Esta vez, en lugar de tomar el nombre __main__, se cambia el valor por el nombre del propio módulo donde se ejecuta.
En este caso sale paquete, porque estamos trabajando con el espacio de nombres del paquete.
Espacio publicitario
Si aplicamos esta variable en un módulo del paquete, sí que nos saldrá el nombre del módulo.
Por ejemplo:
principal.pyimport paquete.modulo1
modulo1.py
print(f"Módulo '{__name__}'.")
Si ejecutamos modulo1.py:
Módulo '__main__'.
Si ejecutamos principal.py:
Módulo 'paquete.modulo1'.
if __name__ == __main__
Esto que parece un verdadero galimatías, en realidad es una cosa muy fácil de entender, pero que a la mayoría se le resiste al dar sus primeros pasos con Python. El porqué se resiste, es por la falta de contexto cuando se quiere saber para qué sirve.
Con todo lo que te he enseñado, no necesito más que un párrafo para explicártelo.
Podemos utilizar la variable __name__
para
controlar la ejecución del código. Por ejemplo, podemos
utilizarla para ejecutar código solo si el módulo se está
ejecutando desde el mismo archivo que lo contiene.
Ejecutamos el archivo __init__.py que contiene lo siguiente:
__init__.pyprint(f"Código de {__name__} fuera de la zona restringida.")
if __name__ == "__main__":
print("Ejecutado desde mi propio archivo.")
Código de __main__ fuera de la zona restringida.
Ejecutado desde mi propio archivo.
Desde este mismo archivo, se ha ejecutado tanto el código
de fuera del condicional, como el de dentro, ya que el
valor de la variable __name__
es igual a
"__main__"
, si está ejecutándose desde este
archivo.
Espacio publicitario
Sin embargo, si ejecutamos la importación que tenemos en
el archivo principal.py,
veremos que el condicional y su código no se ejecutan, al
no tener el valor literal "__main__"
en la
variable __name__
, sino que tiene el nombre
del paquete:
import paquete
Código de paquete fuera de la zona restringida.
Gracias a esta técnica tan típica en Python, podemos controlar la forma en que se van a ejecutar las aplicaciones hechas con módulos y paquetes.
Además, a este if
, le podríamos añadir
opcionalmente un else
, que avise de que no se
ejecutó cierto código:
print(f"Código de {__name__} fuera de la zona restringida.")
if __name__ == "__main__":
print("Ejecutado desde mi propio archivo.")
else:
print("No se ejecutó el código restringido.")
principal.py
import paquete
Código de paquete fuera de la zona restringida.
No se ejecutó el código restringido.
El uso de __name__
no está restringido a un
módulo inicializador como es
__init__.py. Puedes
utilizar esta técnica en cada módulo de tus programas. Sin
ningún problema.
Todo depende del tipo de soluciones que quieras implementar, y de qué forma las quieras implementar.
Importaciones de paquetes con *
Para finalizar con el tema de los paquetes, probemos de
hacer una importación de todos los módulos del paquete con
el asterisco (*
).
Gracias a esto, podremos disponer de todos los módulos en el espacio de nombres donde hagamos la importación, sin tener que estar poniendo el nombre del paquete cada vez.
Ahora mismo, al intentar utilizar modulo1
,
importando con el asterisco, vemos que no está
funcionando:
from paquete import *
modulo1.descripcion()
NameError: name 'modulo1' is not defined
Error de nombre: el nombre 'modulo1' no está definido
Para comprobar el acceso a los nombres de paquete, podemos
mirar si se ha cargado el nombre modulo1
y
modulo2
en el espacio de nombres, con la
función predefinida dir()
:
from paquete import *
print(dir())
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
Vemos que no. Esto es porque hay que utilizar en el módulo
__init__.py, una variable
especial llamada __all__
.
Espacio publicitario
En ella, guardaremos una lista con todos los módulos del paquete:
__init__.py__all__ = [
'modulo1',
'modulo2'
]
Básicamente, le damos una lista de importaciones en el estado inicial, para poder utilizar la importación con el asterisco.
Ahora, si llamamos de nuevo a la función
dir()
, en el archivo
principal.py, veremos
que las importaciones están cargadas en el espacio de
nombres:
from paquete import *
print(dir())
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'modulo1', 'modulo2']
El término all se traduce al español como “todo”.
Entonces, puedes utilizar una función, de por ejemplo, el
modulo1
, solo nombrándolo, aunque no lo
hayamos importado explícitamente en este archivo.
__all__ = [
'modulo1',
'modulo2'
]
paquete.modulo1.py
def descripcion():
print("Soy el módulo 1.")
principal.py
from paquete import *
modulo1.descripcion()
Soy el módulo 1.
Espacio publicitario
Espacio publicitario
Ejercicios de Python para resolver
Mini proyecto - Calculadora modular
A continuación vas a realizar un pequeño proyecto dividido en varios ejercicios. Se trata de una calculadora de consola hecha con módulos y un paquete.
51. Crea un paquete con cuatro módulos llamado
calculadora
.
Además, crea un quinto módulo en la raíz del proyecto.
La estructura deberá quedar como puedes ver en la siguiente imagen:

Cada uno de los módulos del paquete
calculadora
, servirán para llevar la lógica
de los diferentes cálculos de la calculadora.
En cambio, el módulo principal
, servirá de
controlador. Este no llevará toda la lógica del programa,
sino que la reunirá mediante importaciones.
Entonces, lo que se pide en este ejercicio es que crees la estructura que ves en la imagen, sin añadir código a los archivos.
En este ejercicio, solo tenías que crear la estructura solicitada.
52. En cada módulo de operaciones, crea una sencilla
función que no tenga parámetros. Se le pedirá al usuario
dos números para operar con input()
.
Se hará la operación en una variable, y se mostrará el
resultado en un print()
.
Algo como esto:
def sumar():
numero_1 = . . .
numero_2 = . . .
resultado = . . .
print("El resultado de la suma es:", resultado)
Completa el código y adáptalo a cada módulo de operaciones.
En este ejercicio, tenías que completar el código de los cuatro módulos de operaciones:
suma.pydef sumar():
numero_1 = float(input("Introduzca el primer número: "))
numero_2 = float(input("Introduzca el segundo número: "))
resultado = numero_1 + numero_2
print("El resultado de la suma es:", resultado)
resta.py
def restar():
numero_1 = float(input("Introduzca el primer número: "))
numero_2 = float(input("Introduzca el segundo número: "))
resultado = numero_1 - numero_2
print("El resultado de la resta es:", resultado)
multiplicacion.py
def multiplicar():
numero_1 = float(input("Introduzca el primer número: "))
numero_2 = float(input("Introduzca el segundo número: "))
resultado = numero_1 * numero_2
print("El resultado de la multiplicación es:", resultado)
division.py
def dividir():
numero_1 = float(input("Introduzca el primer número: "))
numero_2 = float(input("Introduzca el segundo número: "))
resultado = numero_1 / numero_2
print("El resultado de la división es:", resultado)
53. Importa los cuatro módulos de calculadora en el módulo principal, con cuatro importaciones, es decir, no importes todo como paquete.
Estas son las importaciones en principal.py:
principal.py# Importaciones
import calculadora.suma as suma
import calculadora.resta as resta
import calculadora.multiplicacion as multiplicacion
import calculadora.division as division
54. Crea en principal.py una función con un menú para las siguientes operaciones:
- Avisar al usuario de que debe escoger una opción.
- Suma.
- Resta.
- Multiplicación.
- División.
- Salir.
No te compliques con esta función. Tan solo deben ser
print()
con números de opción. Por ejemplo, la opción de suma irá con el número 1, la resta, será la opción 2, etc.
Esta función crea un menú, que se imprime completo con solo llamarla:
principal.py# Función para el menú de la calculadora
def mostrar_menu():
print("Seleccione la operación que desea realizar:")
print("1. Suma")
print("2. Resta")
print("3. Multiplicación")
print("4. División")
print("5. Salir")
Espacio publicitario
55. Crea un bucle while True
, que lo primero
que haga, sea llamar a la función recién creada. Así, cada
vez que se repita el bucle, generará el menú de opciones
de nuevo.
Piensa que si lo ejecutas ahora, solo con la llamada, te generará un bucle infinito, al no tener mecanismo de salida.
Aquí no te tenías que complicar. Solo llamar a la
función en un bucle while True
:
# Bucle principal
while True:
mostrar_menu()
56. En el bucle, le permitiremos al usuario, con un
input()
, elegir una opción del menú. Esto lo
haremos después de la llamada a la función del menú.
Añadimos el input()
al bucle:
# Bucle principal
while True:
mostrar_menu()
opcion = input("Introduzca el número de la operación deseada: ")
57. Con esa opción introducida por el usuario, evaluaremos con un condicional, cada opción.
Mediante esa opción, se llamará a la función correspondiente.
Por ejemplo:
Opción 1 elegida - Se llama a la función sumar().
Con un condicional match
, se simplifica
mucho la legibilidad, cuando creamos menús:
# Bucle principal
while True:
mostrar_menu()
opcion = input("Introduzca el número de la operación deseada: ")
match opcion:
case "1":
suma.sumar()
case "2":
resta.restar()
case "3":
multiplicacion.multiplicar()
case "4":
division.dividir()
58. Si no lo has hecho aún, implementa una forma de salir del bucle, cuando el usuario ponga la opción para salir. Eso hará que el programa finalice.
58. Añadimos la opción de salida del bucle:
principal.py case "5":
print("¡Hasta la próxima!")
break
59. Para cuando el usuario se equivoque, habría que añadir
un bloque else
o
default
(dependiendo que condicional uses),
para advertir que el número de opción introducida no es
válido.
Una vez hayas finalizado este ejercicio, comprueba que la calculadora funciona correctamente, ejecutando cada opción del menú, y haciendo una operación de cada tipo.
Si quieres, haz una copia del proyecto, para no tocarlo, e intenta añadir más módulos con más tipos de operaciones. Por ejemplo, cálculo de potencia, de raíz cuadrada, etc.
Añadimos un bloque default
(o
else
si utilizaste if
), para
avisar de que se ha introducido un número de opción
incorrecta:
case _:
print("Número de opción no válido")
Por ejemplo, si pones un 7 de opción, te saltará este bloque.
60. Borra todas las importaciones anteriores del archivo
principal.py, y haz que
funcione la calculadora con este import
:
# Importaciones
from calculadora import *
Recuerda que para que funcione este tipo de importación, tienes que crear un paquete con los módulos que estás importando.
¡Importante! Si usas la extensión Pylint, puede que te salgan falsos errores con los nombres de los módulos en el código. Pylint (al menos en la versión que utilizo, v2023.10.1) no toma en cuenta los nombres que hay en
__all__
.
Para que nos funcione la importación con
import *
, hay que crear un paquete. El
paquete será la carpeta calculadora con todos
sus módulos.
En la carpeta calculadora, crea un módulo llamado
__init__.py, y dentro
le pones una lista con la variable especial
__all__
, y los nombres de los módulos que
forman el paquete:
__all__ = [
"suma",
"resta",
"multiplicacion",
"division"
]
Te pongo el código que tengo yo, para que lo puedas comparar con el tuyo:
principal.py# Importaciones
from calculadora import *
# Función para el menú de la calculadora
def mostrar_menu():
print("Seleccione la operación que desea realizar:")
print("1. Suma")
print("2. Resta")
print("3. Multiplicación")
print("4. División")
print("5. Salir")
# Bucle principal
while True:
mostrar_menu()
opcion = input("Introduzca el número de la operación deseada: ")
match opcion:
case "1":
suma.sumar()
case "2":
resta.restar()
case "3":
multiplicacion.multiplicar()
case "4":
division.dividir()
case "5":
print("¡Hasta la próxima!")
break
case _:
print("Número de opción no válido")
Paquete calculadora
__init__.py
__all__ = [
"suma",
"resta",
"multiplicacion",
"division"
]
suma.py
def sumar():
numero_1 = float(input("Introduzca el primer número: "))
numero_2 = float(input("Introduzca el segundo número: "))
resultado = numero_1 + numero_2
print("El resultado de la suma es:", resultado)
resta.py
def restar():
numero_1 = float(input("Introduzca el primer número: "))
numero_2 = float(input("Introduzca el segundo número: "))
resultado = numero_1 - numero_2
print("El resultado de la resta es:", resultado)
multiplicacion.py
def multiplicar():
numero_1 = float(input("Introduzca el primer número: "))
numero_2 = float(input("Introduzca el segundo número: "))
resultado = numero_1 * numero_2
print("El resultado de la multiplicación es:", resultado)
division.py
def dividir():
numero_1 = float(input("Introduzca el primer número: "))
numero_2 = float(input("Introduzca el segundo número: "))
resultado = numero_1 / numero_2
print("El resultado de la división es:", resultado)
Espacio publicitario