CREANDO UN GESTOR DE ARCHIVOS «PICKLE» EN PYTHON (2ª parte)

En el anterior artículo de esta serie, expusimos el modo «tradicional» de crear un archivo de almacenamiento permanente, haciendo uso del módulo «pickle» de «python». Como pudimos ver se trata de un proceso sencillo en el que creamos ese tipo de archivos mediante la ejecución de un archivo «.py».

Sin embargo, podemos elaborar un programa que realizara este proceso de un modo más directo y que a la vez, nos permita realizar cambios en el mismo de un modo directo, sin necesidad de tener que crear un nuevo programa con esa única finalidad.

En cuanto al modo en que va a funcionar nuestro gestor, crearemos un programa que al iniciarse, nos de las siguientes opciones:

primç

Como se puede apreciar en la imagen, nuestro futuro gestor nos va a dar 3 opciones ( a la que asignaremos las letras «A», «B» y «C» respectivamente).

Así la opción «A» nos dará la posibilidad de crear un nuevo archivo, la opción «B» nos permitirá consultar la información correspondiente a un archivo previamente creado, finalmente, la opción «C», nos permitirá alterar el contenido de un archivo ya existente (esta última opción es la más compleja de las tres, ya que su elección nos mostrará un nuevo menú, mediante el cual podremos especificar el tipo de cambio que queremos realizar).

En este segundo articulo de la serie, me centraré en la explicación de la elaboración de las dos primeras opciones («A» y «B»). mientras que a la opción «C» (dada su mayor complejidad) dedicaremos el tercer articulo de esta serie. Empecemos pues.

Como es habitual, cuando iniciamos la confección de un programa en «python» lo primero que debemos hacer es importar aquellos módulos que vamos con los que vamos a trabajar. De ese modo empezaremos escribiendo:

init

Así, lo primero que importamos es, naturalmente, el módulo «pickle», dado que es precisamente el tipo de archivos que va a generar nuestro programa. Acto seguido importaremos tres funciones encargadas de validar el tipo de datos que introduzca el usuario (y evitar que se puedan introducir datos, que, debido a su naturaleza, pudieran generar errores de ejecución en el programa). Estas funciones («ns»,»opt» y «OKI») se encuentran alojadas en un módulo de confección propia (al que he dado el nombre de»VALID.py») y que iré explicando conforme vayamos haciendo uso de ellas. Finalmente importaremos los módulos «subprocess» (para limpieza de pantalla tras cada ejecución) y el modulo «time», para suspender la ejecución del programa durante unos segundos, (aunque este no sea algo esencial).

Como lo que primero queremos que haga nuestro programa, es mostrar al usuario las opciones señaladas más arriba, empezaremos escribiendo, en el marco de un ciclo «while» (en el cual se enmarcará la ejecución de todo el programa):

inicio

De este modo presentaremos al usuario de nuestro programa, las opciones «Crear nuevo archivo», «ver un archivo» e «introducir cambios en un archivo», para lo que este tendrá que introducir los caracteres «A», «B» y «C» respectivamente. Esta información se almacenará en una variable a la que daremos el nombre de «op». Para asegurarnos de que nuestro usuario solo pueda introducir una de dichas opciones, haremos uso de una de las funciOnes del modulo «VALID». Concretamente haremos uso de la función «opt» la cual, tomando como argumento, por una parte, el dato introducido por el usuario, y por otro, la lista de caracteres correspondientes a las opciones posibles [«A»,»B»,»C»],  comprobará si el dato introducido por el usuario se encuentra dentro de dicha lista. Nuestra función «opt» tendrá esta sintaxis:

opt

De este modo, mientras que el carácter introducido por el usuario (que en la función se encuentra representado en la variable «o») no se encuentre dentro de la lista de caracteres admitidos (representados en la función, por la variable «l»), nos aparecerá un mensaje («Introduzca una opción válida: «) el cual nos hará saber que el carácter introducido no se corresponde con ninguna de las opciones establecidas. Este ciclo solo finalizará cuando el usuario introduzca una opción incluida en «l», momento en que la función nos devolverá (mediante la sentencia «return») la opción aceptada («o»).

Lo cierto es que hay otras formas de realizar este tipo de comprobaciones. Siendo la más habitual aquella mediante la cual se dice: «while op!=»A» and op!=»B» and op!=»C»: » mostrar el mensaje de error. Este método habría estado bien en este caso, el problema viene en aquellos casos en los que las opciones posibles son más numerosas (en cuyo caso puede ser interesante el empleo de la función referida).

Hasta aquí hemos visto como establecer (mediante la variable «op» y la función «opt») la opción del usuario. A continuación, vamos a prever que es lo que tiene que hacer nuestro programa, para cada una de las opciones.

op_a

De modo que en el caso de que la opción elegida haya sido la «A» (que como recordaremos era la correspondiente a la funcionalidad de  «CREAR ARCHIVO NUEVO») lo primero que haremos será crear la lista (a la que daremos el nombre de «lista») en la que iremos incluyendo los datos que albergará nuestro nuevo archivo pickle. En este caso, haremos que nuestro programa cree nuestro archivo, pidiendo, primero, a nuestro usuario, que introduzca los datos que contendrá el archivo «pickle», separados por una coma (pedimos que se separe por coma, debido a que emplearemos la coma «,» como criterio para hacer la separación de los distintos datos del que constará nuestro archivo). Acto seguido, «uniremos» (haciendo uso de la función «join») todos los caracteres introducidos por el usuario, eliminando los espacios en blanco que puedan haber. Esta cadena de caracteres unidos la almacenaremos en una nueva variable que llevará el nombre de «un». A continuación (y mediante el método «split») tomando como referencia las comas introducidas, crearemos una lista con los distintos datos introducidos individualizados, la cual será representada en la variable «sep».

Tras hacer esto, tendremos una lista compuesta por los datos introducidos por el usuario (en la variable «sep»). En este punto se nos plantea el inconveniente de que (dentro de la lista) cada uno de los datos se encuentran en formato «string» (ya se trate de caracteres alfabéticos, numéricos o alfanuméricos). Sin embargo, para un futuro uso más eficiente de nuestro archivo «pickle», vamos a idear un modo de almacenar en la lista, cada uno de los datos, atendiendo a su naturaleza (es decir: guardando los caracteres enteros en el formato «int», los decimales en el formato «float» y los caracteres alfabéticos como «str»).

fori

Para ello, haremos uso de la lista («lista») creada más arriba, en la que se irán almacenando los datos en su correspondiente formato. Para ello, emplearemos un ciclo, mediante el cual iremos recorriendo la lista «sep» (en la que, como se recordará, se habían almacenado los distintos datos individualizados, pero en formato cadena). Por su parte, en el marco de este ciclo usaremos una variable (de nombre «elem») la cual irá siendo igual a cada valor de «i» pasado por una nueva función (a la que hemos bautizado como «dat») la cual se encargará de dar a cada dato su formato correspondiente, antes de añadirlo a la lista, la cual tendremos que haber definido con anterioridad y que tendrá la siguiente estructura:

dat

La presente función tiene como cometido el «convertir» cada uno de los datos de la lista «elem» al formato entero cuando se trate de números enteros, decimal cuando se trate de decimales y cadena cuando de trata de caracteres no numéricos o que combinen caracteres alfabéticos y numéricos. Para ello tomamos como argumento el elemento de la lista del que se trate (representado aquí por «n») e intentaremos (mediante «try») convertirlo al formato entero. De no poder hacerse así, trataremos (otra ves mediante la función «try») convertirlo al formato decimal. Si tampoco se puede llevar a cabo esta operación (por tratarse de caracteres alfabéticos o alfanuméricos) pasaremos a convertirlo al formato cadena. Una ves completadas estas operaciones, la función devolverá (mediante «return») el dato en su formato correspondiente.

fori

Para cerciorarnos de que el dato se añade en su formato, para cada ejecución del ciclo (mediante la instrucción «print(type(elem))»)haremos aparecer en pantalla el formato de cada dato tal y como se muestra a continuación:

ejej

Una vez establecidos los datos que albergará nuestro archivo nuevo, lo siguiente será pedirle a nuestro hipotético usuario que escoja un nombre para el nuevo archivo (información que se almacenará en una nueva variable llamada «nombreA») tal y como hacemos en la imagen sobre estas líneas.

En este punto tendremos que tener en cuenta que (si no lo hemos previsto) el usuario podría perfectamente, ingresar un nombre, para el archivo nuevo, que coincidiera con el nombre de otro archivo ya creado con anterioridad. En este  supuesto se eliminaría la información del archivo antiguo y sería sustituida por los nuevos datos introducidos. Por ello vamos a incluir en nuestro programa, una funcionalidad mediante la cual, en el caso de que se introduzca un nombre para el nuevo archivo, que fuera coincidente con el nombre de otro ya creado, aparezca por en la pantalla, un mensaje advirtiendo de tal coincidencia, dando la opción al usuario de sobrescribirlo o abortar la operación, tal y como se aprecia en la imagen siguiente:

adver

Para ello haremos uso de una nueva función (a la que llamaremos «busca_ar») que tomará como argumento el nombre introducido en la variable «nombreA» y cuyo resultado almacenaremos en la variable «busca», tal y como se puede apreciar el la última línea de la siguiente imagen.

bus

El cometido de esta nueva función «busca_ar» es, precisamente, la de buscar algún archivo existente con anterioridad, que tenga el mismo nombre que el escogido para el nuevo archivo y, en caso de encontrarlo, dar el aviso al usuario antes de poder sobrescribirlo. La nueva función de la que estamos hablando (y que tendremos que haber definido con anterioridad) tendría el siguiente aspecto:

busca_ar

Así, lo primero que hará nuestra función «busca_ar» es (mediante la instrucción «try») intentar abrir en modo lectura, un archivo preexistente con el nombre escogido por el usuario para el nuevo (el cual estará representado en la función, por la variable «n»). De modo que en el caso de que se pueda llevar a cabo esa operación (por existir, ya, un archivo con ese mismo nombre) nos aparezca un mensaje alertándonos de la existencia de un archivo con ese mismo nombre y preguntándonos si queremos sobrescribir esa información. La decisión que en ese punto tome el usuario, se almacenará en una variable llamada «sob». Es en este punto en el que haremos uso de una de las funciones que yo tengo guardada en mi modulo «VALID». Concretamente haremos uso de la función llamada «ns». La misión de dicha función es la de procurar que nuestro usuario solo pueda contestar a la cuestión anterior, escribiendo «s» para afirmar y «n» para negar. Dicha función «ns» es la siguiente:

ns

De modo que esta función emplea un ciclo «while» el cual solo se romperá en el caso de que el usuario escriba «n» o «s» (las cuales son las dos únicas opciones que vamos a aceptar para la variable «sob».

busca_ar

Continuando con nuestra función «busca_ar», en el caso de que ante la pregunta de si queremos sobrescribir el archivo, contestamos afirmativamente (introduciendo la letra «s»), mediante «pickle.dump» se procederá a crear el nuevo archivo, con la información previamente almacenada en la variable «lista» y con el nombre escogido («nombreA»). No obstante, en el caso de que hayamos escogido la opción de negación (introduciendo «n») nuestra función devolverá el valor booleana «False», el cual hará que (mediante «subprocess.call») se proceda a una limpieza de pantalla, y mediante la instrucción «continue» se pase por alto la ejecución del resto del programa para volver al inicio.

arcreado

Volviendo sobre nuestra función «busca_ar», En el caso en el que inicialmente, no se haya podido encontrar el archivo con el nombre indicado (lo cual significa que no existe ningún archivo con ese mismo nombre) se producirá una excepción (mediante la instrucción «except») consistente en la directa creación del nuevo archivo sin necesidad de preguntar nada al usuario.

Realizado todo este proceso (y en el caso de que, finalmente, se haya creado un nuevo archivo) utilizaremos la instrucción «print» para mostrar la información contenida en dicho archivo (la cual, como recordaremos, se encontraba en la variable «lista») y otra sentencia «print» para mostrar un mensaje confirmando la correcta creación del nuevo archivo.

Hasta aquí, la explicación del código referente a la opción «A» (correspondiente a la creación de un nuevo archivo). Acto seguido procederemos a ver las instrucciones de la opción «B» de nuestro menú (referida a la simple consulta de la información almacenada en un archivo creado en una ocasión anterior).

opB

La opción «B» (para consultar el contenido de un archivo ya creado con anterioridad) va a ser la más sencilla de todas, ya que, lo único que va a hacer es pedir a nuestro usuario que ingrese el nombre de un archivo y acto seguido, el programa buscará dicho archivo para, finalmente mostrar su contenido (que se almacenará en la variable «contenido») en la pantalla.

Para ello, tal y como se puede ver en la imagen de arriba, haremos uso de una nueva función (llamada «conte») que se encargará tanto de pedir el ingreso del nombre del archivo al que se quiere acceder como de su búsqueda. A su vez, esta función toma como argumento, la letra «a», por una razón que pasaré a explicar en breve. Dicha función «conte», es la siguiente:

conte

A la hora de diseñar nuestra función, debemos de tener en cuenta, la posibilidad de que, por el motivo que fuere, nuestro usuario introdujese un nombre que no coincidiera con el de ninguno de los archivos guardados en la computadora previamente. Para evitar que se pueda dar ese error, hemos creado nuestra función de modo que (dentro de un ciclo «while») intente (mediante la instrucción «try») abrir el archivo con el nombre previamente pedido por la función (y almacenado en la variable «nombre»). De modo, que en el caso de que se pueda llevar a cabo tal operación (por existir un archivo con ese nombre) se termine la ejecución del ciclo (mediante «break») y en el caso de no poderse llevar a cabo la operación (por no haber ningún archivo con ese nombre) generar una excepción (mediante «except») mediante la cual se muestra un texto en el que se advierte del hecho de que no se ha podido encontrar ningún archivo con el nombre pedido por el usuario iniciándose de nuevo la ejecución del ciclo con la petición del nombre del archivo al que se quiere acceder.

arnp

Como hemos dicho, este ciclo solo finalizará en el momento en el que ingresemos un nombre que coincida con el de algún archivo ya creado. Momento en el que, dependiendo del argumento tomado (que podrá ser la letra «a» o la letra «b») nos devolverá, o bien el contenido almacenado en el archivo (como en ese caso) o simplemente el nombre del archivo. Esto es debido a que esta misma función la empleamos para obtener dos tipos de datos distintos.

Hasta aquí la explicación de las opciones «A» («CREAR NUEVO ARCHIVO») y «B» («VER UN ARCHIVO»). En la 3ª parte analizaremos la opción «C» («INTRODUCIR CAMBIOS EN UN ARCHIVO») con las sub-opciones que esta contiene referentes a añadir nueva información, eliminar información o cambiar información.

El código completo tanto del gestor como del módulo «VALID», puede consultarse en los siguientes enlaces de github:

https://github.com/antonioam82/herramientas/blob/master/pickle_gestor.py

https://github.com/antonioam82/herramientas/blob/master/VALID.py

Saludos.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Deja un comentario