2.1. Serialización de objetos

La serialización es el proceso de convertir un objeto en una secuencia de bytes para almacenarlo o transmitirlo a la memoria, a una base de datos o a un archivo. Su propósito principal es guardar el estado de un objeto para poder volver a crearlo cuando sea necesario. El proceso inverso se denomina deserialización.

Por ejemplo, guardar una lista de Python en un archivo de texto o base de datos, y luego cargarlo cuando sea necesario, para ser tratado con su tipo de datos.

Formatos comunes entre los distintos lenguajes de programación incluyen XML y JSON.

Python ofrece tres módulos diferentes en la biblioteca estándar que le permiten serializar y deserializar objetos:

2.1.1. Módulo pickle

Nota

Propósito: es una libraría para implementa protocolos binarios para serializar y deserializar una estructura de objetos Python, es decir, convertirlos en un flujo de bytes que se puede almacenar o transmitir por una red.

El módulo pickle implementa protocolos binarios para serializar y deserializar una estructura de objetos Python.

El módulo pickle nos permite serializar y deserializar datos en archivos binarios. Podemos usarlo para guardar y cargar registros como si fuera una base de datos simple.

En lugar de una base de datos real, usaremos un archivo .pkl para almacenar los datos en una lista de diccionarios.

📌 Ventajas de pickle:

  • ✅ Fácil de usar, sin necesidad de instalar bases de datos.

  • ✅ Útil para almacenar estructuras de datos complejas (listas, diccionarios, objetos).

📌 Desventajas:

  • ❌ No es ideal para grandes volúmenes de datos.

  • ❌ No permite consultas avanzadas como SQL.

2.1.1.1. Práctica - Caso real

A continuación se presenta una práctica más real de implementar el uso de proyectos con pickle para operaciones CRUD en un archivo de registros serializados:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""Programa que simula un inventario de productos"""

import os
import sys
from pathlib import Path
import pickle


class Producto:
    """Clase Producto"""

    def __init__(self, id, descripcion):
        """Método constructor de clase de Producto

        Args:
            id (int): ID del producto
            descripcion (str): Descripción del producto
        """
        self.id = id
        self.descripcion = descripcion

    def __str__(self):
        """Método de representación de informal del objeto,
        usado para crear la salida que se le mostrará al usuario"""
        return f"Id: {self.id}\nDescripción: {self.descripcion}"

    def __repr__(self):
        """Método de representación de formal del objeto,
        usado para depuración y desarrollo"""
        return f"{self.__class__.__name__}:({repr(self.id)}, {repr(self.descripcion)})"


class Inventario:
    """Clase Inventario"""

    def __init__(self):
        """Método constructor de clase de Inventario"""
        self._DB_DIR = (
            os.path.dirname(os.path.abspath(__file__)) + os.sep + "filestorage/"
        )
        self.productos = []
        self.archivo = self._DB_DIR + "inventario.pkl"
        self.leer_datos()

    def __str__(self):
        """Método de representación de informal del objeto,
        usado para crear la salida que se le mostrará al usuario"""
        return f"Ruta BD: {self.archivo}"

    def __repr__(self):
        """Método de representación de formal del objeto,
        usado para depuración y desarrollo"""
        return f"{self.__class__.__name__}:({repr(self.archivo)})"

    def leer_datos(self):
        """Leer el archivo de almacenamiento"""
        try:
            Path(self._DB_DIR).mkdir(parents=True, exist_ok=True)
            with open(self.archivo, "rb") as bd:
                self.productos = pickle.load(bd)
        except FileNotFoundError:
            print("El archivo no existe en la ubicación")

    def guardar_datos(self):
        """Guarda los datos"""
        try:
            if os.path.isfile(self.archivo):
                os.remove(self.archivo)
            with open(self.archivo, "wb") as bd:
                pickle.dump(self.productos, bd)
        except OSError:
            print("El archivo no existe en la ubicación")

    def existe(self, codigo):
        """Valida si existe el producto

        Args:
            codigo (int): ID del producto
        """
        if self.productos:
            for producto in self.productos:
                if producto.id == codigo:
                    return True
        return False

    def buscar(self, codigo):
        """Buscar el producto en el Inventario

        Args:
            codigo (int): ID del producto
        """
        for posicion, producto in enumerate(self.productos):
            if producto.id == codigo:
                return posicion, producto
        return 0, None

    def agregar_registro(self, codigo):
        """Agregar el producto

        Args:
            codigo (int): ID del producto
        """
        descripcion = input("Descripción: ")
        producto = Producto(codigo, descripcion)
        self.productos.append(producto)
        self.guardar_datos()

    def mostrar_registro(self, codigo):
        """Mostrar el producto

        Args:
            codigo (int): ID del producto
        """
        if self.existe(codigo):
            posicion, producto = self.buscar(codigo)
            print(producto)
        else:
            print("¡El producto no existe!")
        input("Presione ENTER para continuar")

    def actualizar_registro(self, codigo):
        """Actualizar el producto

        Args:
            codigo (int): ID del producto
        """
        if self.existe(codigo):
            posicion, producto = self.buscar(codigo)
            print(producto)
            print("Escribe nuevos datos: ")
            descripcion = input("Descripción: ")
            self.productos[posicion].descripcion = descripcion
            self.guardar_datos()
            print("¡Actualizado exitosamente!")
        else:
            print("¡El producto no existe!")
        input("Presione ENTER para continuar")

    def eliminar_registro(self, codigo):
        """Eliminar el producto

        Args:
            codigo (int): ID del producto
        """
        if self.existe(codigo):
            posicion, producto = self.buscar(codigo)
            print(producto)
            confirmar = input("¿Estas seguro? (S/N): ").upper()
            if confirmar in ("s", "S", "si", "Si", "SI"):
                del self.productos[posicion]
                self.guardar_datos()
                print("¡Eliminado exitosamente!")
        else:
            print("¡El producto no existe!")
        input("Presione ENTER para continuar")

    def menu_principal(self):
        """Menu principal del programa"""
        try:
            # Instancia de la clase Inventario
            inventario = Inventario()
            while True:
                print("\n==============")
                print("MENÚ PRINCIPAL")
                print("==============\n")
                opciones_menu = "1) Crear\n"
                opciones_menu += "2) Consultar\n"
                opciones_menu += "3) Actualizar\n"
                opciones_menu += "4) Eliminar\n"
                opciones_menu += "5) Salir\n"
                opciones_menu += "\nElija uno: "
                # Solicitar al usuario que elija una opción
                opcion = int(input(opciones_menu))
                # Opciones del menú
                if opcion == 1:
                    codigo = int(input("Id de Producto: "))
                    if not inventario.existe(codigo):
                        inventario.agregar_registro(codigo)
                        print("¡Registro exitoso!")
                    else:
                        print("¡Producto ya existe!")
                    input("Presione ENTER para continuar")
                elif opcion == 2:
                    codigo = int(input("Id de Producto: "))
                    inventario.mostrar_registro(codigo)
                elif opcion == 3:
                    codigo = int(input("Id de Producto: "))
                    inventario.actualizar_registro(codigo)
                elif opcion == 4:
                    codigo = int(input("Id de Producto: "))
                    inventario.eliminar_registro(codigo)
                elif opcion == 5:
                    break
        except KeyboardInterrupt:
            print(" <Ctrl-C> introducido, saliendo del programa...\n")
            sys.exit()


if __name__ == "__main__":
    # Instancia de la clase Inventario
    app = Inventario()
    # Llamar al método menu_principal
    app.menu_principal()

Importante

Usted puede descargar el código usado en esta sección haciendo clic en el siguiente enlace:

Truco

Para ejecutar el código main.py, abra una consola de comando, acceda al directorio donde se encuentra el programa:

proyectos/
└── pickle/
    └── sistema/
        └── main.py

Si tiene la estructura de archivo previa, entonces ejecute el siguiente comando:

python3 main.py

El anterior código al ejecutar debe mostrar el siguiente mensaje:

==============
MENÚ PRINCIPAL
==============

1) Crear
2) Consultar
3) Actualizar
4) Eliminar
5) Salir

Elija uno:

Luego de crear un registro, el archivo inventario.pkl debe ser creado en el directorio filestorage/ como se muestra a continuación:

proyectos/
└── pickle/
    └── sistema/
        ├── filestorage/
        │   └── inventario.pkl
        └── main.py

Truco

En lugar de una base de datos real, usaremos un archivo inventario.pkl` para almacenar los datos en una lista de diccionarios.

Así de esta forma puede ingresar, consultar, actualizar y eliminar registro en un archivo serializado de objetos python pickle.


Ver también

Consulte la sección de lecturas suplementarias del entrenamiento para ampliar su conocimiento en esta temática.


¿Cómo puedo ayudar?

¡Mi soporte está aquí para ayudar!

Mi horario de oficina es de lunes a sábado, de 9 AM a 5 PM. UTM - Madrid, España.

La hora aquí es actualmente 7:35 PM UTM.

Mi objetivo es responder a todos los mensajes dentro de un día hábil.

Contrata mi increíble soporte profesional