Módulos de usuario
Si tenemos una parte de código con cosas que nos puedan resultar
especialmente interesantes para volver a ser utilizadas en otros programas,
podemos guardar este código que contenga clases, funciones, listas, diccionarios… en un archivo independiente. Cada vez que necesitemos utilizar estos elementos, bastará con importarlos y podremos utilizarlos como si estuviesen escritos en nuestro código principal. Estos archivos independientes reciben el nombre de «módulos». Por ejemplo:
class Libro:
"vamos a definir la clase libro."
def __init__(self,tema,paginas,editorial):
"inicializamos los atributos principales."
self.tema=tema
self.paginas=paginas
self.editorial=editorial
mi_lista=[13,234,2424,1234,454,352,44.34,432.334,441.489,78.54]
mi_diccionario={"Madrid":3587222,"Lisboa":2343821,"París":7312987,"Londres":7224872}
mi_conjunto={"Francia","Italia","Argentina","Bolivia","Ecuador"}Esta pequeña porción de código (que por supuesto puede ser tan extensa como queramos), la podemos guardar en un archivo llamado mi_archivo.py, el cual estará situado en la misma carpeta (o directorio) que nuestro programa principal.
Una vez hemos creado y guardado el archivo, cualquiera de los elementos que figuran en dicho archivo, puede ser llamado desde nuestro código:
from mi_archivo import Libro,mi_lista
tulibro=Libro("Aventuras",287,"Aventureros")
print(f"Tu libro de {tulibro.tema} tiene {tulibro.paginas} páginas.")
print(f"Es de la editorial {tulibro.editorial}.")
print(f"El primer elemento de la lista es {mi_lista[0]}.")Resultado:
Tu libro de Aventuras tiene 287 páginas.
Es de la editorial Aventureros.
El primer elemento de la lista es 13.Podemos importar tantos objetos del módulo como queramos. Si son más de uno, deben de ir separados por comas. Una vez importados, funcionarán igual que si hubiésemos escrito su código dentro del nuestro.
Si lo deseamos, podemos importar todos los objetos del archivo a la vez utilizando asterisco en lugar de ir nombrándolos a todos:
from mi_archivo import *
.....Si tenemos mucho código reutilizable, podemos organizar todo el código en varios archivos (con extensión .py) En dicho caso nos gustará tener todos los archivos recopilados en una o varias carpetas. Para utilizar un módulo concreto que se encuentre en un archivo, que pertenezca a una determinada carpeta, haremos mención a la carpeta y luego separado por un punto, al archivo.
Por ejemplo, si archivo anterior se encuentra en una carpeta llamada
mis_recursos, se invocaría así:
from mis_recursos.mi_archivo import Libro,mi_listaMódulos de Python
Python también dispone de sus propios módulos, que podemos importar para utilizar en nuestro código. Estos módulos de Python contienen funciones predefinidas que pueden ser de mucha utilidad.
Tomaremos como ejemplo el módulo math con funciones y constantes matemáticas. En los ejemplos utilizaremos la función seno (sin) y la constante pi.
import math
print(math.sin(math.pi/2))Resultado:
1.0Esta forma anterior de importar un módulo tiene el inconveniente de que ocupa más memoria que otras. La ventaja es que para utilizar sus funciones y constantes debemos de nombrar el módulo seguido de un punto y a continuación el nombre de la función o constante. Esto va a impedir que se den duplicidades con nuestras propias variables o funciones.
Con el siguiente método obtendremos el mismo resultado, sin embargo importaremos solo la constante pi, y la función sin. Tiene la ventaja de que ocupa menos memoria que con la importación completa, pero la desventaja es que puede haber duplicidades si tenemos otra constante o función con el mismo nombre que
los importados.
from math import pi,sin
print(sin(pi/2))El tercer método que se muestra a continuación es el peor sistema que podemos utilizar para la importación, ya que reúne los dos inconvenientes. Ocupa más memoria, ya que lo importa todo, y además puede haber incompatibilidades con los nombres de constantes o funciones importadas y las que ya tengamos
definidas en nuestro código.
from math import *
print(sin(pi/2))Y por último con el próximo método, importamos la función sin y le damos el nombre seno. También hemos importado la constante pi, pero la hemos renombrado como PI. De esta manera, la constante pi y la constante PI serán cosas diferentes (no nos dará problemas de compatibilidad). Esta forma de renombrar funciones o constantes importadas es posible gracias a la palabra reservada “as”.
from math import sin as seno
from math import pi as PI
pi="otra cosa"
print(seno(PI/2))
print("pi es "+pi)Resultado:
1.0
pi es otra cosaPodemos saber todas las funciones y constantes incluidas dentro de un módulo predefinido de Python (o uno creado por nosotros). Por ejemplo siguiendo con el módulo “math”, el siguiente código nos facilitará todas las funciones y constantes de math:
import math
print (dir(math))Resultado:
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh',
'asin', 'asinh', 'atan', 'atan2', 'atanh', 'cbrt', 'ceil', 'comb', 'copysign', 'cos', 'cosh',
'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'exp2', 'expm1', 'fabs', 'factorial', 'floor',
'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf',
'isnan', 'isqrt', 'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf',
'nan', 'nextafter', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh',
'sqrt', 'sumprod', 'tan', 'tanh', 'tau', 'trunc', 'ulp']Leer archivos.
Python puede manipular de forma muy sencilla archivos de texto con extensión .txt. El mismo procedimiento sería posible para leer otro tipo de archivos, como .csv
Examinemos el siguiente código:
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
file="mi_archivo.txt"
with open (file,'r') as file_object:
contenido=file_object.read()
contenido=contenido.rstrip()
print(contenido)Un posible resultado con un archivo de ejemplo sería:
Resultado:
Este archivo de texto,
está escrito a modo de ejemplo.
Solo tiene 3 líneas.Las 3 primeras líneas de código aseguran que Python buscará el archivo en el mismo directorio que se encuentra el archivo de código que le llama. Si hemos configurado Python para que nos busque en dicho directorio, ya no harían falta.
A continuación le damos como valor a una variable de texto, el nombre del archivo que queremos abrir.
El comando «with» se asegura de cerrar el archivo al finalizar, open es quien abre el archivo. El parámetro “r” indica que el archivo se abrirá en modo lectura. La siguiente parte de la línea as file_object: le da un nombre al archivo dentro del código. En este caso, el archivo pasa a llamarse dentro del código file_object.
El objeto archivo se lee con el método «.read». Su contenido pasa a ser el valor de la variable de texto en este caso llamada contenido.
El siguiente método .rstrip lo hemos utilizado para eliminar una línea en blanco que se inserta automáticamente al final de archivo cuando lo leemos con .read.
Cuando acaba el bucle with, el archivo se cierra. Por último hemos decidido mostrar con print, el contenido de la variable literal que hemos creado con .read.
Si por algún motivo, el archivo que intentamos leer ha sido escrito desde
Linux, pero el programa va a ejecutarse en Windows, necesitaremos modificar “whit open…”de la siguiente manera:
with open (file,’r’, encoding=’utf-8′) as file_object:
Así estamos indicando que el archivo está codificado en utf-8, que es el
sistema que utiliza Linux para sus ficheros .txt.
De la misma manera, si el archivo ha sido escrito desde Windows, pero
ejecutamos en Linux, la instrucción debería ser:
with open (file,’r’, encoding=’cp1252′) as file_object:
En este caso hemos abierto el archivo en modo lectura, ya que se ha incluido
el parámetro “r”. Si no hubiésemos incluido ningún parámetro, éste sería el que tomaría por defecto. Es decir se podría haber codificado:
with open (file) as file_object:Si el archivo se encuentra en una carpeta diferente, que se encuentre en el mismo directorio que el archivo de código, deberemos sustituir la cuarta línea del código anterior por esta otra:
file="textos\\mi_archivo.txt"En este caso textos es la carpeta que contiene el archivo. Se ha escrito la doble barra para evitar confusiones con las caracteres de escape.
Si el archivo estuviese en un sistema Linux, sería algo así como:
file="textos/mi_archivo.txt"Otra forma posible de llamar al archivo es de la siguiente manera:
file="L:\\Buenos_Py\\mi_archivo.txt"
with open (file,'r') as file_object:
contenido=file_object.read()
contenido=contenido.rstrip()
print(contenido)En este segundo código, hemos llamado al archivo haciendo mención a su referencia absoluta. Si lo hacemos así, no serían necesarias las tres líneas primeras del código inicial.
En Linux la llamada al archivo con referencia absoluta sería algo así como:
file="/home/mi_usuario/mis_documentos_/mi_archivo.txt"Leer un archivo línea por línea.
Con el siguiente código, vamos a leer un archivo .txt línea por línea:
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
file="mi_archivo.txt"
contador=1
with open (file,"r") as file_object:
for line in file_object:
print(contador,line.rstrip())
contador+=1La instrucción for line in file_object: es la encargada de ir leyendo las líneas. La variable de texto “line” recibe el valor de cada línea leída. Hemos añadido un contador que se imprimirá antes de cada línea, para que se pueda observar mejor el efecto de esta porción de código.
Debemos de tener en cuenta, que Python va a identificar como una línea el texto que escribamos hasta que pulsamos la tecla de salto de línea (Return), en ese momento se inserta una nueva línea; todo ello independientemente del número de líneas físicas que ocupen en pantalla. También hemos depurado con .rstrip cada una de las líneas, porque Python añade automáticamente un salto de línea al final de cada línea que lee.
Resultado:
1 Este archivo de texto,
2 está escrito a modo de ejemplo.
3 Solo tiene 3 líneas.Leer un archivo carácter por carácter
Con el siguiente código, podemos leer un archivo de texto carácter por carácter:
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
file="mi_archivo.txt"
with open (file,"r") as file_object:
cadena_1=""
for k in range (0,25):
cadena_1=cadena_1+(file_object.readline(1))
cadena_2=""
for k in range (0,20):
cadena_2=cadena_2+(file_object.readline(2))
print(cadena_1)
print(cadena_2)Resultado:
Este archivo de texto,
es
tá escrito a modo de ejemplo.
Solo tieneEl método .readline( ) aplicado al objeto archivo, se encarga de leer el número de caracteres indicados entre paréntesis.
En este ejemplo hemos creado una cadena con los primeros 25 caracteres del archivo. A continuación hemos creado otra cadena con los 40 siguientes (20 veces se leen 2 caracteres).
Debemos de recordar que el carácter de salto de línea («\n») es un carácter más.
Crear una lista con cada línea del archivo.
Podemos crear una lista, donde cada elemento sea una línea del archivo.
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
file="mi_archivo.txt"
with open (file,"r") as file_object:
lines=file_object.readlines()
for k in range (0,len(lines)):
lines[k]=lines[k].rstrip()
print(k,lines[k])Resultado:
0 Este archivo de texto,
1 está escrito a modo de ejemplo.
2 Solo tiene 3 líneas.Este código lee el archivo. Almacena sus líneas en una lista llamada “lines”. Cada línea será un elemento de dicha lista. Después nos va a mostrar cada una de sus líneas, anteponiendo su número y comenzando por 0. También hemos depurado cada una de las líneas con .rstrip.
Archivo no encontrado.
Si el archivo que intentamos abrir, no se encuentra en la carpeta que se espera, o si está mal escrito su nombre, el sistema no podrá abrirlo y se lanzará un mensaje de error que detendrá el programa. Si queremos evitar que esto pueda ocurrir, podemos añadir la excepción «FileNotFoundError» para que trate el error y
pueda seguir el programa su curso sin detener su ejecución.
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
file="mi_archivo2.txt"
try:
with open (file) as file_object:
lines=file_object.readlines()
print (lines[1])
except FileNotFoundError:
print(f"¡Vaya! No existe el archivo {file}.")
print("Pero seguimos con el programa.")Posible resultado:
¡Vaya! No existe el archivo mi_archivo2.txt.
Pero seguimos con el programa.En el supuesto de que el archivo no se haya encontrado, el bloque try/except FileNotFoundError, nos lanzará el mensaje de advertencia, pero el programa proseguirá su ejecución sin detenerse.
Creación y escritura en archivos.
Podemos crear un archivo y a continuación escribir en él:
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
filename="mi_archivo_3.txt"
with open(filename,'w') as file_object:
file_object.write("Me gusta programar en Python.\n")
file_object.write("Me divierte mucho y aprendo.\n")Las tres primeras líneas nos sitúan en el mismo directorio donde se
encuentra el archivo de código.
Llamamos al archivo con el parámetro “w”. Se va a crear el archivo en dicho directorio (Atención: Si el archivo ya existe SERÁ SOBREESCRITO)
A continuación utilizamos el método .write del objeto archivo para escribir en él. Vemos que al final de cada frase añadimos un salto de línea. Si no lo hiciésemos así, se añadirían al archivo las frases una a continuación de otra.
Añadir contenido a un archivo.
Si ya tenemos un archivo con un determinado nombre, y queremos añadir
contenido a dicho archivo, deberemos de abrirlo con el argumento ‘a’:
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
file="mi_archivo_3.txt"
with open(file,"a") as file_object:
file_object.write("Escribiremos una línea más.\n")
file_object.write("Tal vez escriba más otro día.\n")Debemos de asegurarnos de que el archivo ya existe, si no fuese así al ejecutar el código anterior daría error. Por lo tanto podríamos haber escrito:
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
filename="mi_archivo.txt"
if not filename:
filename = open ('mi_archivo.txt','w')
with open(filename,"a") as file_object:
file_object.write("Escribiremos una línea más.\n")
file_object.write("Tal vez escriba más otro día.\n")Si el archivo existe, añade los datos. Si no existe, lo crea y luego añade los datos.
Abrir archivo en modo Lectura/Escritura.
Si queremos abrir un archivo para leerlo, pero a la vez queremos escribir en él, podemos utilizar el parámetro “r+”:
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
file="mi_archivo.txt"
with open (file,'r+') as file_object:
contenido=file_object.read()
contenido=contenido.rstrip()
file_object.write("Escribiremos una línea más.\n")
file_object.write("Tal vez escriba más otro día.\n")Este código abrirá el archivo que se indica y copiará su contenido a la variable «contenido». A continuación escribirá las dos líneas que se indican. Se añaden los saltos de línea «\n». Debemos de tener claro que las líneas que se añaden, se añaden al archivo, pero todavía no quedan reflejadas en la variable «contenido» que ya tomó toda la información del archivo cuando se abrió.
El archivo indicado debe de existir. Si no tenemos claro su existencia deberíamos de añadir el bloque try/except con la excepción FileNotFoundError
Archivos JSON
Un tipo particular de archivos que es muy útil, son los archivos con formato
json. Cuando el usuario necesita guardar una información sencilla, los archivos txt pueden ser suficientes. En cambio cuando se debe de guardar una información más compleja (una lista, un diccionario, un conjunto, una lista de diccionarios…) entonces podemos acudir a los archivos json, que nos facilitan mucho la tarea.
La gran ventaja de estos archivos, es que las estructuras de datos que guardemos en ellos, serán recuperadas y reutilizadas en nuestro código de una forma muy sencilla.
Su ventaja es que pueden ser utilizados en otros lenguajes de programación,
o aplicaciones que los acepten. No son válidos para guardar objetos y clases.
import json
import os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
lista_alumnos=[]
nombre=""
filename="datos_alumno.json"
try:
with open (filename,"r") as file:
lista_alumnos=json.load(file)
except FileNotFoundError:
pass
alumnos={}
##diccionario con datos de cada alumno
while nombre.upper()!= "SALIR":
nombre=input("(Para salir nombre=salir). Nombre: ")
if nombre.upper()!="SALIR":
apellidos=input("Indica los apellidos: ")
edad=input("Indica la edad: ")
curso=input("Indica el curso: ")
alumnos["nombre"]=nombre
alumnos["apellidos"]=apellidos
alumnos["edad"]=edad
alumnos["curso"]=curso
lista_alumnos.append(alumnos) ##añadimos el alumno a la lista de alumnos.
alumnos={} ##vaciamos diccionario
##ahora se crea el fichero 'json' con la LISTA de los alumnos.
##SI EXISTÍA YA EL FICHERO, SE SOBREESCRIBE CON EL NUEVO,
##QUE AHORA CONTIENE LOS DATOS ANTIGUOS Y LOS NUEVOS.
with open(filename,"w") as file:
json.dump(lista_alumnos,file)Lo primero es importar el módulo json. Nos situamos en el directorio de
trabajo. Inicializamos los datos:
lista_alumnos: En este ejemplo va a contener una lista de diccionarios de
alumnos con sus datos. Cada diccionario contiene los datos de un alumno. Esta lista será guardada (y recuperada) en un archivo .json
datos_alumno.json: Es el nombre que tendrá el archivo.
A continuación comprobamos si el archivo ya existe. Si existe lo abre y
recupera en lista_alumnos los datos que contenía. Si no existe, no haremos nada de momento (pass)
Inicializamos el primer diccionario (vacío de momento).
El siguiente bloque, se encarga de ir pidiendo al usuario los datos de un
alumno. Cuando acaba, añade este alumno (su diccionario) a la lista de alumnos.
Cuando finalizamos de añadir alumnos (tecleamos salir), se crea
datos_alumno.json (si el archivo ya existía se sebreescribe con el nuevo, que tiene los datos actualizados). Cuando volvamos a ejecutar el programa, los datos del archivo se volcarán en lista_alumnos
En este ejemplo hemos guardado una lista (con sus diccionarios). Pero
podríamos haber guardado cualquier tipo de dato (excepto datos de objetos y/o sus clases).
Archivos pickle.
Con el módulo pickle podemos crear archivos binarios donde sí que
podremos guardar tanto objetos, como cualquier otro elemento o estructura de Python.
El inconveniente es que solo pueden ser tratados por Python. También
debemos tener cuidado a la hora de manipular este tipo de archivos si no han sido creados por nosotros, ya que como son binarios, pueden contener cualquier tipo de código (tal vez malicioso).
En el siguiente ejemplo, le hemos puesto la extensión .pkl, pero en realidad
al ser binarios, le podríamos haber puesto cualquier otra extensión que no fuese incompatible con alguna otra de nuestro sistema.
import pickle,os
midirectorio=os.path.dirname(__file__)
os.chdir (midirectorio)
class Alumno:
def __init__(self,registro,nombre,apellidos,edad,curso):
self.registro=registro
self.nombre=nombre
self.apellidos=apellidos
self.edad=edad
self.curso=curso
def mostrar_lista(lista):
for k in range (0,len(lista)):
print("Registro de Alumno:",lista[k].registro)
print("Nombre:",lista[k].nombre)
print("Apellidos:",lista[k].apellidos)
print("Edad:",lista[k].edad)
print("Curso:",lista[k].curso,"\n")
try:
with open('mis_registros.pkl', 'rb') as f:
lista= pickle.load(f)
print("\nLista de registros actuales: \n")
mostrar_lista(lista)
except FileNotFoundError:
lista=[]
contador=len(lista)
nombre=""
while nombre.upper()!= "SALIR":
nombre=input("\n(Para salir nombre=salir). Nombre: ")
if nombre.upper()!="SALIR":
contador+=1
registro=f"{contador:05}"
apellidos=input("Apellidos: ")
edad=(input("Introduzca la edad: " ))
curso=(input("Introduzca el curso: "))
nuevo_alumno=Alumno(registro,nombre,apellidos,edad,curso)
lista.append(nuevo_alumno)
print("\nLista de registros actualizada: \n")
mostrar_lista(lista)
with open('mis_registros.pkl','wb') as f:
pickle.dump(lista, f)Posible resultado:
(Para salir nombre=salir). Nombre: Eduardo
Apellidos: Gómez Martínez
Introduzca la edad: 22
Introduzca el curso: 5
(Para salir nombre=salir). Nombre: Alfredo
Apellidos: Pérez García
Introduzca la edad: 19
Introduzca el curso: 3
(Para salir nombre=salir). Nombre: Pedro
Apellidos: Ibay Pérez
Introduzca la edad: 18
Introduzca el curso: 2
(Para salir nombre=salir). Nombre: salir
Lista de registros actualizada:
Registro de Alumno: 00001
Nombre: Eduardo
Apellidos: Gómez Martínez
Edad: 22
Curso: 5
Registro de Alumno: 00002
Nombre: Alfredo
Apellidos: Pérez García
Edad: 19
Curso: 3
Registro de Alumno: 00003
Nombre: Pedro
Apellidos: Ibay Pérez
Edad: 18
Curso: 2 Posible resultado en una segunda ejecución del código:
Lista de registros actuales:
Registro de Alumno: 00001
Nombre: Eduardo
Apellidos: Gómez Martínez
Edad: 22
Curso: 5
Registro de Alumno: 00002
Nombre: Alfredo
Apellidos: Pérez García
Edad: 19
Curso: 3
Registro de Alumno: 00003
Nombre: Pedro
Apellidos: Ibay Pérez
Edad: 18
Curso: 2
(Para salir nombre=salir). Nombre: Pedro
Apellidos: Picapiedra Gámez
Introduzca la edad: 17
Introduzca el curso: 2
(Para salir nombre=salir). Nombre: salir
Lista de registros actualizada:
Registro de Alumno: 00001
Nombre: Eduardo
Apellidos: Gómez Martínez
Edad: 22
Curso: 5
Registro de Alumno: 00002
Nombre: Alfredo
Apellidos: Pérez García
Edad: 19
Curso: 3
Registro de Alumno: 00003
Nombre: Pedro
Apellidos: Ibay Pérez
Edad: 18
Curso: 2
Registro de Alumno: 00004
Nombre: Pedro
Apellidos: Picapiedra Gámez
Edad: 17
Curso: 2 Comenzamos importando el módulo pickle.
El código de este ejemplo contiene una clase llamada Alumno. Los objetos de esta clase van a ser almacenados en una lista. Se ha creado también una función para mostrar la lista con todos los objetos (Alumnos).
El archivo que va a contener todos los objetos creados y que luego serán recuperados se llama ‘mis_registros.pkl’. Vemos que cuando abrimos el archivo para lectura, utilizamos los parámetros “rb”. Esto es debido a que además de “r” que abre el archivo para lectura, necesitamos el parámetro “b”, para indicar que el archivo está codificado en binario.
La instrucción lista=pickle.load(f) carga el contenido del archivo en lista. Si el archivo no existe, inicializa la lista como una lista en blanco.
Nos ayudamos de contador para ir anotando el número de registro que tiene cada alumno.
El atributo .upper del literal nombre, nos pasa el contenido de la variable nombre a mayúsculas (aunque el usuario lo haya introducido en minúsculas), al solo efecto de comprobar si nombre=salir.
Registro toma el valor de contador, en formato 0000N
Cuando tenemos todos los datos, creamos el objeto nuevo_alumno, que pasa a almacenarse en la lista llamada “lista”.
Para finalizar creamos el archivo ‘mis_registros.pkl’ (si ya existía, quedará sobrescrito) y escribimos en él todos los registros actualizados. Este archivo queda listo para ser abierto y cargado (en lista) cuando se ejecute de nuevo el programa.
Vemos que el archivo se abre con los parámetros “wb”. La lista queda cargada en dicho archivo gracias a la instrucción: pickle.dump(lista, f)

