martes, 8 de febrero de 2022

Módulos en Python.


imagen de entrada


Generalidades de los módulos.

Los módulos son programas con extensión normalmente .py o .pyc que contiene un conjunto de funciones, variables o clases que se pueden ejecutar en otros programas. Esto es muy útil ya que nos permite reutilizar código y organizarlo todo mejor. 

Vamos a verlo con un ejemplo. Vamos a crear un archivo de Python llamado mates.py que tenga unas funciones que sumen o resten dos números y lo ejecutaremos para ver si funciona.

mates.py

""" Suma o resta dos números dados"""


def sumar(x, y):
    """Suma dos números dados."""
    return x + y


def restar(x, y):
    """Resta dos números dados."""
    return x - y


print(sumar(2, 3))
print(restar(12, 2))

Salida:

5
10
Ahora que vemos que funciona, estaría bien si cada vez que creásemos un programa que tuviera que sumar o restar números no tuviésemos que volver a escribir todo este código. Como ya tenemos las funciones escritas, vamos a ver como podemos utilizarlas. Entramos en el shell de Python y escribimos:

# Para importar el módulo ponemos el nombre del archivo pero sin la extensión.
import mates

Salida:

5
10

¡Pero que es esto! ¡ Como ves al importar un módulo se ejecuta todo el código que está escrito en el programa! Para poder ejecutar un programa bien como un programa principal o como un módulo en otro programa se suele utilizar "if __name__ == "__main__": Este código lo verás con frecuencia. Volvemos a rescribir mates.py para entender su funcionamiento.

""" Suma o resta dos números dados"""


def sumar(x, y):
    """Suma dos números dados."""
    return x + y


def restar(x, y):
    """Resta dos números dados."""
    return x - y

if __name__ == "__main__":
    print(sumar(2, 3))
    print(restar(12, 2))
Cuando el interprete de Python ejecuta mates.py, si es el programa principal, la variable __name__ se establecerá como __main__ y se ejecutará el código que va a continuación del condicional.

Ahora bien, si el código se está importando desde otro programa, como un módulo, la variable __name__ se establecerá con el nombre del módulo (mates en nuestro caso) y no se ejecutarán las líneas de código que van a continuación.

Visto lo anterior, existen tres formas de importar un módulo.

1) Usando import podemos importar todo el contenido (Ponemos el nombre del archivo pero sin la extensión). Si ahora volvemos al shell de Python e importamos todo el módulo:

>>> import mates
>>> 
Veremos que ya no se muestran los resultados de sumar 2 y 3 o de restar 12 menos 2. Sin embargo si que tenemos a nuestra disposición ambas funciones del módulo. Podemos acceder a ellas con el nombre del módulo seguido del componente o función. Probemos:

Python 3.8.10 (default, Nov 26 2021, 20:14:08) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mates
>>> mates.sumar(8,10)
18
>>> mates.restar(15,4)
11
>>> 
2) También podemos importar únicamente los componentes que nos interesen. Por ejemplo si solo nos interesa importar la función sumar() del módulo mates, podemos importarla directamente sin tener luego que especificar el módulo del que depende al utilizarla:

Python 3.8.10 (default, Nov 26 2021, 20:14:08) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from mates import sumar
>>> sumar(6,7)
13
>>> 
Puedes ver que de esta forma no es necesario usar el nombre del módulo para llamar a la función. No es necesario poner mates.sumar(6,7) con sumar(6,7) ya nos funciona. De hecho si lo intentas invocar así te dará un error.

3) Aunque no se suele hacer o recomendar puedes importar todos los componentes del módulo con un *. Por ejemplo para importar todo lo del módulo (sumar y  restar en este caso):

Python 3.8.10 (default, Nov 26 2021, 20:14:08) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from mates import *
>>> sumar(4,5)
9
>>> restar(14,7)
7
>>> 

Rutas de los módulos.


Python por defecto busca el módulo en el mismo directorio o carpeta que el programa o script que lo llama y si no lo encuentra ahí, lo buscará en el directorio de instalación de Python. Puedes ver si quieres las carpetas donde se buscarán los módulos con los siguientes comandos desde el shell de Python:

>>> import sys
>>> print(sys.path)
Sin embargo también es posible acceder a módulos que estén en una subcarpeta dentro de donde este el script que lo importa. Vamos a imaginar la siguiente estructura. 

. ├── main.py ├── carpeta │ └── modulo.py

Desde el programa main.py se importará el modulo que está en una subcarpeta a un nivel inferior.

Podemos hacerlo de la siguiente forma:

main.py

import carpeta.modulo o from carpeta.modulo import *
¿Y que pasa si queremos crear una carpeta en otra parte donde se encuentren los módulos creados por nosotros? Pues entonces para poder importarlos tenemos que añadir la ruta de la misma al sys.path para que Python pueda buscarla. 

>>> import sys
>>> sys.path.append('/ruta/de/los/modulos')
No obstante si esto lo ejecutas desde el shell de Python solo te valdrá para esa sesión ya que al salir de la misma no se conserva la modificación.


Cambiando los nombres de los modulos con 'as'


En ocasiones cuando utilizas módulos, te encuentras con que los nombres de los mismos son muy largos o difíciles de recordar. En esas ocasiones es posible utilizar un "alias" para los mismos usando 'as' lo que facilita las cosas.

Imagina que tenemos que importar un módulo que se llama thinker_drawing que tiene lo siguiente:

thinker_drawing.py

render = "renderizando ventana"
y que lo queremos importar en el programa en el que estamos trabajando, que es principal.py. En vez de usar el nombre original para trabajar con el módulo:

principal.py

import thinker_drawing 
print(thinker_drawing.render)
podemos trabajar de forma más cómoda usando 'as':

principal.py

import thinker_drawing as td
print(td.render)

Funciones útiles después de importar un módulo.


Son dir() y help().

El primero de ellos dir() nos sirve para ver cuales son los elementos que componen un módulo. Si lo utilizamos sin argumentos nos permite ver los nombre (variables, funciones, clases etc) existentes en nuestro espacio de nombres de Python y si le pasamos como argumento un modulo después de importarlo nos dará su contenido o cosas que podemos usar de ese modulo.

print(dir())

['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
El segundo help() nos mostrará información de ayuda del módulo.

Por ejemplo en nuestro módulo de matemáticas (mates.py):

""" Suma o resta dos números dados"""


def sumar(x, y):
    """Suma dos números dados."""
    return x + y


def restar(x, y):
    """Resta dos números dados."""
    return x - y

if __name__ == "__main__":
    print(sumar(2, 3))
    print(restar(12, 2))
si lo importamos desde otro script o desde el shell de Python y ejecutamos help() veremos la ayuda del módulo:

principal.py

import mates
print(help(mates))
Salida:

Help on module mates:

NAME
    mates - Suma o resta dos números dados

FUNCTIONS
    restar(x, y)
        Resta dos números dados.
    
    sumar(x, y)
        Suma dos números dados.

Recargando módulos.


Es importante señalar que por muchas veces que importemos un módulo este solamente se ejecutará una vez. Por ejemplo si tenemos un modulo que imprime un mensaje por pantalla, a pesar de que lo importemos muchas veces solo se cargará o ejecutará una vez.

imprimir.py

# mimodulo.py

print("Importando mimodulo")

varios_import.py

import imprimir
import imprimir
import imprimir
Salida:

Importando mimodulo

** Process exited - Return Code: 0 **

Press Enter to exit terminal

Si queremos que un modulo se recargue varias veces, tenemos que usar la biblioteca importlib y declararlo de la siguiente manera:

varios_import.py

import imprimir
import importlib
importlib.reload(imprimir)
importlib.reload(imprimir)
Salida:

Importando mimodulo
Importando mimodulo
Importando mimodulo


** Process exited - Return Code: 0 **
Press Enter to exit terminal

Estructura formal de un modulo.


Para finalizar si en alguna ocasión queremos crear un módulo que sea más o menos formal, deberíamos usar esta estructura parecida a la siguiente para facilitar la máxima información posible sobre quien programa el módulo, que hace, con que licencias se distribuye etc 

#!/usr/bin/env python3
#-*- coding: utf-8 -*-
__author__ = " "
__copyright__ = " "
__credits__ = " "
__licence__ = " "
# tipo de licencia bajo la que se distribuye, por ej. GPL
__versión__ = " "
# número de versión del modulo
__email__=" "
__status__=" "
# Si está en desarrollo (Development) o finalizado (Production)


# Código del módulo


No hay comentarios:

Publicar un comentario