MOSTRANDO DATOS OCULTOS EN IMÁGENES, CON «Pillow».

Los dispositivos como cámaras digitales, teléfonos inteligentes y escáneres utilizan el estándar EXIF para guardar archivos de imagen o audio. Este estándar contiene muchas etiquetas útiles para extraer que pueden ser útiles para la investigación forense, como la marca, el modelo del dispositivo, la fecha y hora exactas de creación de la imagen e incluso la información del GPS en algunos dispositivos. Pues bien, en esta ocasión nos proponemos crear una sencilla aplicación gráfica, que , seleccionado un archivo de imagen, nos muestre (en el caso que los haya) en un display los datos EXIF de la imagen:

Como es habitual, para crear nuestra aplicación, deberemos empezar importando los recursos necesarios que vamos a emplear. Que en este caso serán (fundamentalmente) las librerías «Tkinter» (preeinstalada con el interprete de Python) y la librería para manipulado de archivos de imagen «Pillow» (la cual deberemos instalar previamente, con el comando «pip install pil«). Una vez que lo tengamos todo listo, iniciaremos la elaboración de nuestro programa, realizando las importaciones pertinentes:

Hechas las importaciones de los módulos y librerías que vamos a necesitar, pasaremos a crear la interfaz de nuestro programa:

Como se ve, empezamos creando la clase de nuestra aplicación «App«, consistente solo (de momento) en una ventana, en cuyo interior, introducimos un display de fondo negro (creado con el método «ScrolledText«) destinado a ser donde se mostrará la información oculta de nuestro archivo de imagen, también mostraremos una pestaña (creada con «Label») en donde en su momento figurará el nombre del archivo cuya información se esté mostrando y un botón «btn_search» (creado con el método «Button» que tantas veces hemos visto) mediante el que, en su momento, haremos la búsqueda del archivo de imagen (que deberá ser de extensión «.jpg«). Efectivamente la ejecución de lo hecho hasta ahora, dará el siguiente resultado:

Ya tenemos nuestra interfaz creada, aunque de momento, esta no hace nada. Por ello, la siguiente fase será la de definir las funciones a través de las cuales, vamos a poder buscar el archivo cuya información queremos leer, para a continuación mostrar dicha información en el display creado. No obstante, antes de ello, vamos a ver, en el editor, el procedimiento «manual» para obtener los metadatos de una foto, usando «Pillow» y su módulo «ExifTags» para luego aplicarlo a nuestra aplicación:

Como se ve, empezamos abriendo nuestro archivo de imagen, usando la función «open()» almacenando la información de la misma, en la variable «image«, de la que, a su vez, procederemos a leer sus metadatos con el método «._getexif()» almacenando dichos datos en «exifdata«. Una vez que hemos obtenido nuestros metadatos, pasaremos a mostrarlos en pantalla en un formato que presente el nombre del campo («tag«) y su valor asociado («data«). Ello lo haremos iterando sobre cada uno de los elementos presentes en «exifdata«, decodificandolos, para luego mostrarlos en pantalla tal y como se muestra a continuación:

Una vez que conocemos el procedimiento para, extraer los metadatos de la imagen, solo tenemos que implementarlo en nuestra aplicación. Como hemos dicho antes, la aplicación permitirá (con «SEARCH FILE«) buscar y seleccionar el archivo cuyos a cuyos datos ocultos queremos acceder. Para ello, crearemos una primera función, a la que daremos el nombre de «open_file()«:

Como se ve, en esta función usamos «askopenfilename()» para abrir el navegador de nuestro sistema de archivos de modo que podamos seleccionar la imagen (que por defecto será de extensión «.jpg«) cuya información queremos extraer. La ruta a dicho archivo quedará almacenada en la variable «file» de modo que solo si el valor de esta no está vacío (lo que pasaría si cerráramos el navegador sin haber seleccionado ningún archivo)es decir «if self.file!=»»«, se guardará (en «filename«) el nombre (sin la ruta completa) del archivo, se mostrará en la etiqueta «file_label» el nombre de dicho archivo («self.file_label.configure(text=self.filename)«) y se ejecutará la función encargada de extraer y mostrar la información de la imagen. Dicha función tiene por nombre «extract_data()» y es la que mostramos a continuación:

La función (que tomará como argumento el nombre del aechivo seleccionado en el paso anterior) se iniciará realizando una limpieza del display («self.display.delete(‘1.0’,END)«). Tras ello, como vimos en el ejemplo anterior, procederá a abrir dicho archivo («image=Image.open(f)«) para, a continuación, extraer la información oculta que pueda tener. En este caso pueden suceder dos cosas: El primero de ellos es que el archivo abierto carezca de este tipo de información (con lo que el valor de «exifdata» será «None«) en cuyo caso se mostrará el mensaje «NO DATA» en el display («self.display.insert(END,’NO DATA’)«) .

La segunda posibilidad es que el archivo abierto si disponga de dicha información. En cuyo caso se aplicará el procedimiento para mostrar los campos («tags«) y su correspondientes valores («data«) siguiendo el procedimiento que vimos antes, con la salvedad de que, en este caso, vamos a hacer unas previsiones que no hicimos en el ejemplo, y es la que tiene que ver con la posibilidad de que al decodificar la información, nuestro programa se tope con algún carácter que no pueda mostrar en el display. Siendo este el motivo por el que utilizamos un «try» para la operación de mostrado de información en el display. De modo que si dicha acción no se pudiera llevar a cabo tal operación, usaremos «re.sub()» para sustituir dichos caracteres por un espacio en blanco.

Aunque a la hora de buscar el archivo cuya información queremos extraer, el formato que se mostrará por defecto es «.jpg» (ya que es el formato principal que soporta el extandard «EXIF«) cabe la posibilidad que se acabe seleccionando un archivo que no lo haga. en cuyo caso nuestra aplicación mostrará «ERROR» en el display:

Y con esto tendríamos creada nuestro propio visor de datos EXIF. Como se ve, se trata de un programa bien sencillo cuyo código integro podéis ver en el siguiente enlace:

https://github.com/antonioam82/Data_exctractor/blob/master/EXIF_data_viewer.py

Saludos.

SIGNIFICADO Y USO DE «*args» Y «**kwargs» EN FUNCIONES PYTHON.

Hola, una vez más y bienvenidos a vuestra página sobre programación en «python». Hoy vamos a hablar sobre el significado de las sintaxis «*args» y «**kwargs» que, tal vez, hayáis visto como argumentos, en alguna función, sobre las cuales (especialmente si estáis empezando), os hayáis preguntado acerca de su significado y propósito, temas de los cuales, vamos a hablar en la presente ocasión.

USO DE «*args».

Utilizamos el asterisco «*» acompañado del término «args» (en realidad podemos usar otro cualquiera, pero por convención se usa «args«) para pasar un número indeterminado de argumentos a la función. Esto nos permitirá, por ejemplo, pasar un número de argumentos mayor al previamente definido. Veamos lo, con un sencillo ejemplo:

La expresión «*args» nos permite introducir un número, no determinado previamente, de variables, para nuestra función.

Primero, hemos definido nuestra función («funcion()«), a la cual, imprimirá en pantalla, un número indeterminado de variables (strings en este caso). Esto permitirá que, al aplicar la función, podamos pasarle, indistintamente, el numero de argumentos que queramos. Incluso, podemos no introducir ninguno, como sucede cuando introducimos «funcion()» (de modo que la función no dará error, aunque tampoco mostrará nada).

De este modo también podemos dejar la posibilidad de añadir argumentos extra a nuestra función, aunque previamente, se haya definido otra:

De este, modo, en el ejemplo, se ve como hemos empezado introduciendo un primer argumento «arg1» (que en la aplicación de la función se correspondería con el string «Ejemplo«) a la función, para a continuación, añadirle un número indeterminado de nuevos argumentos.

Como hemos dicho, por lo general, usamos, por convención, el término «args» después del «*«, al venir de la palabra «arguments» (argumentos). Aunque podríamos usar cualquier otro término (lo que no debemos olvidar es el «*«). Esto, por ejemplo, aplicado al primer ejemplo visto, podría quedar así:

USO DE «**kwargs».

Por su parte «**kwargs» (con doble asterisco) nos va a permitir hacer los mismo que lo que veíamos en el caso de «*args» con la diferencia que ene este caso, cada argumento vendría dado por un par clave-valor (como vimos en su momento, cuando hablábamos de los diccionarios):

Así, en este nuevo ejemplo, la función «funcion()» va a tomar un número arbitrario (no definido previamente) de pares clave-valor, conjunto de pares sobre los que realizaremos una iteración («for clave, valor in kwargs.items():«) en la que imprimiremos el nombre de la clave y su valor asociado, del modo que se ve en el ejemplo.

De modo similar a lo que veíamos en el caso anterior, también podemos usar este procedimiento para añadir pares clave-valor a un argumento previamente definido:

Por su parte, al igual de lo que decíamos respecto a «*args«, normalmente empleamos el término «kwargs» (contracción de «keyword arguments«) después de «**«. no obstante, también podríamos usar un string distinto (siempre detrás de «**«), como en el siguiente ejemplo:

Y hasta aquí estas breves notas acerca del uso (y significado) tanto de «*args» como de «**kwargs» mediante las cuales, en ciertas ocasiones, nos permitirán hacer más flexible, el funcionamiento de nuestras funciones en python.

Saludos.

GRÁFICAS TRIDIMENSIONALES, CON «matplotlib»: GRÁFICA DE BARRAS.

Saludos, una semana más, a «El Programador Chapuzas«, un sitio destinado a la adquisición de conocimientos relativos a la programación en «python». Les habla Antonio Alfonso Martínez, en una ocasión en la que, continuando con nuestra serie de artículos dedicados a la representación gráfica de datos con la librería «matplotlib«, nos disponemos a tratar la creación de gráficas tridimensionales.

Son muchos los gráficos 3D que podemos crear con esta herramienta, en esta primera ocasión nos vamos a centrar en la versión 3D de un tipo de gráfica que tratamos con anterioridad: La gráfica de barras.

Antes de continuar, debemos conocer cuales son los recursos que vamos a necesitar, en este caso, usaremos 2 librerías, principalmente: «matplotlib» (para la creación de gráficas) y «numpy» (para trabajar con los arrays). Si no tenemos instaladas dichas librerías, deberemos hacerlo introduciendo «pip install matplotlib» y «pip install numpy» respectivamente.

GRÁFICA DE BARRAS EN 3D:

Como ya hemos dicho, la gráfica en 3D que vamos a crear, en esta ocasión, es la versión tridimensional de una gráfica de barras. Para ello empezaremos haciendo las importaciones necesarias:

Tal y como hemos mencionado, hemos hecho la importación de «matplotlib.pyplot» y «numpy«. Importaciones a las que hemos añadido la de «mpl_toolkits.mplot3d» la cual, nos permitirá incluir ejes tridimensionales en nuestra representación.

Una vez que tenemos los recursos necesarios, ya estamos en condiciones de empezar a dibujar la gráfica:

Para ello, primero creamos el objeto para dibujar la gráfica (al que hemos llamado «fig«) al que, a continuación le añadimos el «subplot«, espacificando el tipo de proyección, que en nuestro caso será tridimensional (así «projection=’3d’«).

Con ello, tendríamos configurada la gráfica sobre la que más adelante, volcaremos nuestros datos. De modo que si ahora visualizamos lo hecho hasta ahora, con «plt.show()«, obtendríamos el siguiente resultado:

No obstante, vemos que nuestra gráfica se encuentra vacía. Es por ello, que el siguiente paso será el de proporcionarle los datos que queremos representar.

Como puede verse, lo primero que hacemos es ubicar cada una de las barras a representar, en el plano, introduciendo las coordenadas en los ejes «x«, «y» y «z» (para establecer los puntos en el eje «z«, hemos usado el método «.zeros()» (por el que crearemos un array de 10 elementos de valor 0).

Tras ello, mediante las variables «dx«, «dy» y «dz«, estableceremos la anchura, profundidad y altura, respectivamente de cada una de las barras. Como se puede apreciar, hemos establecido la misma anchura y profundidad para todas las barras, con «np.ones(10)» (con el que hemos creado, sendos arrays de 10 elementos de valor 1). Para el caso de la altura, hemos establecido una para cada barra.

No obstante, si, por ejemplo, quisiéramos dar una anchura distinta para cada barra, tendríamos que introducir el correspondiente array de 10 elementos (uno por cada barra). Así, si para «dx» introdujéramos «[2, 3, 4, 5, 6, 3, 2, 4, 5, 7]», obtendríamos el siguiente resultado:

Por su parte, una vez que hayamos definido los datos a representar, emplearemos el método «bar3d» para crear la gráfica 3D, a partir de nuestro objeto «ax1» definido antes.

Tras ello, mostraremos el resultado:

Y con ello, tendríamos creada nuestra gráfica de barras tridimensional. En futuras ocasiones, iremos viendo el modo de crear el resto de gráficos tridimensionales (además de otros en 2D). De momento, a continuación dejo el enlace al código de este ejemplo, para que experimenten por su cuenta, introduciendo datos distintos:

https://github.com/antonioam82/ejercicios-python/blob/master/ejemplo_grafbarras3d.py

Saludos.

IMPORTANDO DATOS FINANCIEROS EN PYTHON, CON «pandas-datareader».

Python es un lenguaje de gran utilidad para trabajar en numerosos campos. Entre ellos, el referente al análisis financiero y económico. Sin embargo, es común que cuando queremos trabajar en tales ámbitos, necesitemos contar con los datos actualizados que nos ofrecen organismos como la «OCDE» o el Banco Mundial. Para poder usar tal información, contamos en python, con una herramienta: «pandas-datareader«, de la que vamos a hablar en la presente ocasión.

Lo que va a hacer «pandas-datareader» (el cual, deberemos instalar previamente) es conectar con la web (para lo que necesitaremos contar con conexión a internet) para importar los datos que pidamos. Aunque en nuestro ejemplo vamos a usar el servicio de «Yahoo! finance«, existen otras webs compatibles con esta herramienta, las cuales se pueden consultar en la documentación de «pandas-datareader«:

Como se ve en la imagen, hemos empezado importando «pandas-datareader» (para realizar la importación) y el módulo «datetime«, que usaremos para establecer la fecha de inicio («start«) y la fecha final («end«), de la serie temporal que queremos consultar de la compañía que queramos («Apple» en nuestro caso, para lo que introduciremos su nombre de modo abreviado: «AAPL«). Para realizar la obtención de los datos deseados, con «Yahoo! finance«, emplearemos el método «.get_data_yahoo()«. Una vez importados los datos, los mostraremos en pantalla con la función «print«:

Obtenemos así el precio de las acciones: Su cotización máxima(‘High‘), mínima (‘Low‘), el volumen total de transacciones (‘Volume‘) y los datos referentes al ajuste de precio final (‘Adj Close‘) para cada uno de los días de la serie (‘Date‘). Información esta, que, tal y como se ve al final, se nos muestra en 1323 filas (de las que se han omitido las centrales) y 6 columnas.

Como se ve, aquí se nos muestra la información para el rango temporal, establecido con «datetime» y las variables «start» y «end«, que vimos antes. No obstante, también podemos mostrar, dentro de la información, ciertos sectores. Así, por ejemplo, si queremos ver solo las primeras filas de la serie, podemos usar el método «.head()«:

Aplicación del método «.head()» sobre «aapl».
Con el método «.head()» se mostrarán solo las filas correspondiente a la primera semana de la serie.

Si, por contra, queremos ver solo, los datos de la última semana de la serie, haremos uso de «.tail()«:

Aplicación del método «.tail()» sobre «aapl».
«.tail()» mostrará solo los datos más recientes del intervalo temporal elegido.

Lo que acabamos de hacer para la serie completa, lo podemos hacer, también, para un año concreto, dentro del rango establecido. Así, si quisiéramos ver los datos referentes a la primera semana de 2009, usaríamos el método «.loc[]» introduciendo entre los corchetes el año, y aplicando nuevamente el método «.head()» para ver sus primeros datos:

Datos correspondientes a a primera semana de 2009.

El mismo método emplearemos para ver los datos de la última semana (en esta ocasión de 2007), solo que aquí aplicaremos «.tail()» como ya vimos:

Datos correspondientes a la última semana de 2007.

Este proceso de selección de información a visualizar que hemos hecho respecto a las filas, podemos hacerlo igualmente, respecto a las columnas. Así, si quisiéramos ver unicamente la columna de datos, relativa a los precios de cierre (columna «Close«) de la serie, centrándonos en sus últimos 10 valores:

Ejecutando este código, obtendremos, junto a las fechas correspondientes (dentro del rango temporal establecido)los valores de la columna «Close«, en este caso, de tal información, hemos seleccionado solo las últimas 10 filas («[-10:]«):

A su vez, con los datos importados con «pandas-datareader» podemos hacer otras operaciones, ente ellas, visualizar dichos datos en una gráfica. Así, partiendo de este último ejemplo, podemos representar los datos del «precio de ajuste «Adj Close«, mediante una gráfica creada con «matplotlib» (que importaremos previamente):

Ejecutando el código, obtendremos la siguiente gráfica:

Evolución del precio de ajuste final, de «Apple» entre 2006 y enero de 2012.

Hasta aquí, hemos visto el modo de obtener los datos, correspondientes a un rango temporal. No obstante, es posible que queramos contar con los datos más recientes al momento de ejercitar nuestro script: Para ello, podemos hacerlo estableciendo la fecha actual en la variable «end«. Pero también podemos obtener el valor más reciente, omitiendo dicha variable:

Aquí, lo que va hacer nuestro código es importar los datos de «Google» (para lo que introduciremos el string «GOOGL«) desde octubre de 2009, para lo que introduciremos «start=datetime.datetime(2009,10,1)«, y la fecha más reciente (actual).

Ejecutado el código obtendremos, por una parte, las 0 últimas líneas de «Close«, y por otro, su correspondiente representación gráfica:

Y hasta aquí, este artículo acerca de la obtención de datos financieros, con «pandas-datareader«. En futuras entregas veremos el modo de realizar cálculos y operaciones con estos datos, para la obtención de la información necesaria para realizar análisis financieros.

Saludos.

CREANDO GRAFICADOR DE FUNCIONES CON «matplotlib», «tkinter» Y «numpy».

Bienvenidos una vez más, a «El Programador Chapuzas». Aquellos que sigan este blog, recordarán que hace un tiempo, estuvimos viendo el modo de integrar una gráfica creada con «matplotlib«, en una ventana creada con «tkinter«. Por su parte, en una ocasión posterior, vimos también el modo de actualizar una gráfica «matplotlib» en tiempo real, a medida que íbamos cambiando los datos de entrada. Bien, en la presente ocasión, vamos a combinar los que aprendimos en aquellas 2 ocasiones, para crear un programa consistente en una ventana que representará la gráfica correspondiente a la función que introduzcamos en una entrada que se mostrará debajo de la gráfica:

Representación de»sin(x)» para un rango de -10 a 10.

Como es natural, lo primero que haremos será crear la ventana que integre nuestra gráfica (que crearemos con «matplotlib«) con los elementos que emplearemos para introducir la función a representan (y también el rango de «x») así como el botón «SET» que mostrará la representación (elementos, estos, creados con «tkinter«). No obstante, antes de iniciar esta labor, importaremos los recursos necesarios de las librerías «tkinter» (para los widgets), «matplotlib» (para mostrar la gráfica) y «numpy» (para efectuar los cálculos sobre las series de datos):

Ya que vamos a crear una ventana «tkinter» que contenga la gráfica, el siguiente paso será crear dicha ventana (a la que con «wm_title«) le daremos el nombre de nuestra aplicación «Graficador«. A su vez, también especificaremos las dimensiones de la misma (que serán adecuadas para una buena visualización gráfica):

Aunque podemos usar el que viene por defecto, también podemos especificar el estilo visual que va atener nuestra gráfica (para ello empleamos el la función «style.use()«) a la que pasaremos el nombre del estilo deseado («fivethirtyeight» en nuestro caso). Para ver el listado de estilos disponibles usaremos el método «style.available» como se muestra a continuación:

Estilos de gráfica, disponibles.

Una vez escogido el estilo de la gráfica, procederemos a crear el objeto que la representará, el cual insertaremos en el área de dibujo que crearemos a continuación:

Para ver como esta quedando la aplicación, vamos a introducir la función para visualización de gráficas, «plt.show()«:

Si ahora ejecutamos lo hecho, obtendremos el siguiente resultado:

Como se ve, hasta ahora ya tenemos creada la ventana, con el área en el que se va a dibujar nuestra gráfica. Como dijimos antes, nuestro programa va a representar la gráfica correspondiente a la función que nosotros le proporcionemos (y si queremos, también dentro del rango que pidamos). Por ello, tendremos que dotar a nuestra ventana de dos espacios en los que podamos introducir la función y el rango (que se especificará mediante dos valores separados por una coma). Dichos espacios los ubicaremos en la parte inferior de la ventana:

Como se ve, hemos añadido una entrada («Entry«) para la función a representar y otra para el rango (que se ubicará en la parte inferior derecha), acompañada de la etiqueta («Label«) «RANGO DE ‘X'». A su vez, también hemos creado un botón («Button«) «SET» con el que ordenaremos a nuestro programa que cree la gráfica a partir de los datos introducidos en la entrada. Una vez creados los elementos, pasaremos a ubicarlos en la ventana con el método «.pack()«:

Con ello, tendríamos creados (y ubicados) los elementos para la introducción de datos en el programa. Sin embargo, tal y como está ahora mismo, si introdujésemos una expresión en la entrada, y le diéramos al botón «SET» veríamos que no ocurre nada, y es que nos falta crear las funciones encargadas de tomar los datos introducidos y plasmarlos en la correspondiente gráfica.

Como lo que queremos es crear una gráfica que se actualice con los datos introducidos en las entradas (si abrir ni generar ventanas adicionales) usaremos una función (a la que llamaremos «animate()«), la cual, es la que vamos a pasar como argumento del método «FuncAnimation()«, de modo que los cambios y operaciones que realice dicha función («animate()«) son los que se plasmarán en el transcurso de la actualización (a intervalos regulares) que llevará a cabo FuncAnimation(). Para ver como funciona esto, como ejemplo, vamos a hacer que nuestra función de actualización «animate()» imprima un mensaje:

Y ejecutamos.

Así, vendría ser como un ciclo «while» con la diferencia de que aquí podemos alterar la actividad de la función durante su ejecución cíclica.

Otra función que vamos a necesitar (a la que llamaremos «represent()«), es aquella que tome los datos introducidos en las entradas (tanto de la destinada a la función a representar, así como la destinada al rango de «x«) proporcionando las variables necesarias para que la gráfica sea posteriormente dibujada por la función «anim()» (que completaremos más adelante):

Función «represent()».

Antes de continuar, hemos de tener en cuenta que a la hora de introducir una entrada, el usuario introduzca, para , por ejemplo, representar el coseno de «x«, «cos(x)«. El problema con esto se encuentra en que para hacer dicho calculo con «numpy«, habría que introducir «np.cos(x)«. De modo que para evitar dicho problema, tendremos que hacer que el programa, recibiendo como entrada «cos(x)» lo traduzca internamente como «np.cos(x)«. Para ello, haremos uso de una nueva función (de nombre «reemplazo()» mediante la que añadiremos «np.» a las funciones que lo requieran para ser calculadas por «numpy«. Para usar tal función, nos valdremos, igualmente, de un diccionario («funciones{}«) en el que incluiremos las funciones y su correspondiente cadena de reemplazo. La cadena resultante de esta función «reemplazo()» es la que finalmente guardaremos en la variable «graph_data«, que emplearemos para dibujar la gráfica:

Función «reemplazo()» y diccionario «funciones{}».

La otra entrada que va a tomar «represent()» es la correspondiente al rango de «X». Dado que más adelante vamos a necesitar tomar los dos valores del rango por separado, separaremos (usando «split()» empleando la coma «,» como separador) dichos valores («ran=rann.split(«,»)«). Puesto que vamos a dar la posibilidad de que el usuario no especifique ningún rango (ets.get()=»») estableceremos que dicha acción consistente en la separación se produzca solo si no se da tal condición («if ets.get()!=»»«).

Representación de «cos(x)» para un rango no especificado (que por defecto será de 1 a 10).

Finalmente, haremos que esta función se ejecute al pinchar en el botón «SET«, por ello añadiremos a dicho botón «command=repesent«:

Ya tenemos creada la función «represent()«, encargada de tomar y preparar los datos de las entradas. Ahora le toca el turno a la función «animate()«, que dibujará la gráfica y que se irá actualizando a intervalos regulares durante la ejecución. Dentro de la cual, empezaremos por la parte dedicada al rango:

Para empezar, la función distinguirá el hecho de que el usuario haya especificado un rango para «x» («act_rango=True«) o no («act_rango=False«). En el primer caso, nuestro programa creará dos variables («lmin» y «lmax«) que serán los limites mínimo y máximo del rango de «x«, los cuales, se corresponden con las posiciones 0 y 1 de la lista «ran» generada en la función «represent()» ya vista. A su vez, para evitar resultados erróneos que pudieran derivarse del hecho de que en la entrada se introdujese un primer valor más alto que el segundo, el establecimiento del rango, con el método «np.arange()» solo se produzca en el caso de que, efectivamente el valor de «lmin» sea menor que el de «lmax» («if lmin<lmax:«). Una vez que se haya completado esta operación de establecimiento del rango crearemos una nueva variable («ul_ran«) que almacenará el citado rango, por un motivo que veremos más adelante.

Otro posible error que podría darse es que el usuario introdujese un dato arbitrario que no tuviera nada que ver con el establecimiento de un rango (por ejemplo, una palabra cualquiera). Es por ello, que hemos hecho uso de la sentencia «try«, de modo, que si el programa no pudiera funcionar con los datos proporcionados, se produjese una excepción («except«) consistente en la muestra de una ventana de error, que crearemos introduciendo «messagebox.showwarning(«Error»,»Entrada no válida»)«. En este caso se borrará la entrada («ets.delete(0,len(ets.get()))«), una vez cerrada la ventana de error, estableciéndose, automáticamente el último rango, válido, introducido (almacenado en «ul_ran«).

Ante una entrada para el rango no válida, el programa mostrará un mensaje de error.

Lo visto, sería para el caso en el que se haya especificado rango, en caso contrario, este será de 1 a 1o, si se trata de una primera ejecución (en donde «ul_ran==»»«) o será el correspondiente al último rango introducido (si «ul_ran!=»»«):

A continuación, nuestra función «animate()» pasará a trazar la gráfica correspondiente a la expresión que queremos representar, la cual, quedó definida en «represent()» y almacenada en la variable «graph_data«:

Puesto, que, al introducir la función a representar, cabe el mismo peligro que veíamos en el caso del rango, de introducir una cadena, imposible de ser tratada (con «eval«), usaremos una sentencia «try«. De modo que si a expresión es apta, se almacenará en un variable «calculo_funcion«, para acto seguido, ser representada gráficamente con el método «.plot()» para el valor actual de cada uno de los que vaya tomando la variable «x» («ax1.plot(x,calculo_funcion)«). Si la expresión no es apta («except«), el programa no empleará «graph_data«. Simplemente representará los valores por defecto (si no se he hecho una representación correcta previamente) o dejará la última representación realizada con éxito.

Si se introduce una cadena no válida, el programa mantendrá la última gráfica representada con éxito.

Finalmente, para una mejor visibilidad, hemos marcado los ejes «x» e «y» con un tono de gris («gray«) mediante los procedimientos «axhline()» y «axwline()» respectivamente:

Y con esto tendríamos creado nuestro graficador de funciones, que nos permitirá visualizar gráficas correspondientes a funciones sencillas combinando los recursos proporcionados por las librerías «tkinter«, «matplotlib» y «numpy«:

Tenéis el código fuente en el siguiente enlace:

https://github.com/antonioam82/graficador/blob/master/graficador.py

INCLUYENDO BARRA DE HERRAMIENTAS:

No obstante aún podemos hacer más, como por ejemplo, incluir la barra de herramientas de «matplotlib» (que nos permitirá hacer cosas tales como hacer zoom, mover la imagen o guardar la gráfica creada) en la parte inferior de nuestro graficador. Para ello, lo primero que haremos será importar «NavigationToolbar2Tk» para después crear el objeto con la variable «toolbar«, tal y como se ve en la siguiente captura:

A su vez, para que la ejecución continuada no interfiera en el posible manejo de la barra de herramientas, necesitaremos que tras cada nueva actualización de la gráfica, se detenga la animación. Para los cual incluiremos el método «event_source.stop()» al final de la función «animate()«:

Sin embargo, una vez detenida la animación, necesitamos que esta se reanude posteriormente, si queremos dibujar una nueva gráfica. Es por ello que incluiremos el método «event_source.start()» en la función «represent()» (que se activará con el botón «SET«):

Esta versión mejorada del programa, que incluye la barra de herramientas de «matplotlib«, puede verse en el siguiente enlace:

https://github.com/antonioam82/graficador/blob/master/graficador_con_toolbar.py

Saludos.

ACTUALIZANDO GRÁFICAS EN TIEMPO REAL EN PYTHON CON «matplotlib.animation».

Cuando trabajamos con representaciones gráficas de datos, es habitual que cuando introducimos cambios en los datos representados, necesitemos, previamente, cerrar la ventana correspondiente a la gráfica y ejecutar nuevamente el programa (volviendo a abrir la ventana de la gráfica) para actualizarla. Sin embargo, podemos hacer que nuestra gráfica se vaya actualizando, en tiempo real, a medida que vamos introduciendo cambios en los datos representados (sin necesidad de volver a abrirla) mediante la función «animation» y el método «FuncAnimation()» de la librería «matplotlib«.

Para ver como funciona nuestra función, vamos a crear una gráfica en la que se mostrará una línea generada por la unión de una serie de puntos (definidos por las coordenadas «x» e «y») que serán leídos desde un archivo de texto (de nombre «ejemplo.txt«) que ubicaremos en nuestra carpeta python:

Ubicación de «ejemplo.txt».
Datos para la gráfica.

Partiendo de estos datos, vamos a crear un archivo «.py» que creará nuestra gráfica. Para ello, empezaremos importando los recursos que vamos a necesitar de la librería «matplotlib» (la cual necesitaremos tener previamente instalada).

Hecho esto, procederemos a crear nuestra gráfica, en el que uno de los primeros pasos será el de crear el objeto que vamos a emplear para dibujar la gráfica («fig = plt.figure()«). También crearemos la variable («ax1«) que usaremos para «conectar» los datos que vamos a tomar, con el objeto encargado de dibujar la gráfica:

Con ello, tendremos creado el objeto de nuestra gráfica. Sin embargo, nuestra gráfica aún no tiene datos para representar. Como hemos dicho, esos datos son los que se encuentran en nuestro fichero «ejemplo.txt«, con lo que procederemos a abrirlo en modo lectura, almacenando su contenido en una variable a la que llamaremos «graph_data» («graph_data=open(«ejemplo.txt»,»r»).read«). A su vez, usaremos una variable de nombre «lines» que irá separando las líneas de «ejemplo.txt» usando el salto de línea («/n«) como criterio separador («lines=graph_data.split(‘/n’)«):

En este punto, también crearemos las variables «xs» e «ys» las cuales, son las listas en las que se van a ir almacenando los valores para los ejes de nuestra gráfica, con «xs.append(x)» y «ys.append(y)» respectivamente. Para lo que, previamente, tendremos que haber separado los pares de valores, usando la coma como separador («x, y = line.split(‘,’)«):

Así, con las listas «xs» e «ys» procederemos a representar nuestra gráfica con el método «.plot()» que tomará ambas listas como argumentos.

Como muchos habrán observado, todo el proceso de apertura y lectura del fichero que contiene los datos para nuestra gráfica, así como el de uso de tales datos para dibujar la gráfica, se encuentra comprendido dentro de una función a la que damos el nombre de «animate()» que es la que emplearemos para el proceso de actualización en tiempo real, para el cual, usaremos «animation.FuncAnimation()«, que usará como argumentos el objeto «fig» que dibuja la gráfica y la función «animate()» que es la que queremos que se actualice de modo cíclico:

Hecho esto, si ahora ejecutamos nuestro programa, veremos como inicialmente, nos mostrará la gráfica correspondiente a los datos presentes en «ejemplo.txt«:

Con la particularidad que si, estando en ejecución el programa, introducimos modificaciones en los datos de «ejemplo.txt«, ( y guardando los cambios), veremos como esos cambios se verán reflejados, en tiempo real (sobre la misma ventana, sin necesidad de cerrarla y abrirla de nuevo), en nuestra gráfica:

La gráfica se actualiza a medida que introducimos cambios en «ejemplo.txt».

El ejemplo expuesto (para cuya ejecución se necesita tener, previamente, creado el archivo de texto «ejemplo.txt») en este artículo puede verse en el siguiente enlace:

https://github.com/antonioam82/ejercicios-python/blob/master/live_graph.py

Saludos.

INSERTAR GRÁFICA «matplotlib» EN VENTANA CREADA CON «tkinter» (EJERCICIO EN PYTHON).

Bienvenidos a «El Programador Chapuzas», mi nombre es Antonio Alfonso Martínez y en esta ocasión vamos a ver (de un modo resumido) el modo de insertar una representación gráfica (realizada con la librería «matplotlib«) en una ventana creada con «tkinter«.

Para ello, necesitaremos disponer de las librerías «tkinter» (instalada por defecto) «numpy» (para crear los arrays de nuestra futura gráfica) y «matplotlib» (para dibujar la gráfica). Estas dos últimas tendremos que instalarlas (si no lo hemos hecho ya) mediante el comando «pip«.

Una vez que tengamos los recursos necesarios, crearemos un nuevo archivo «.py» y realizaremos la importación de los siguientes módulos:

Importación de recursos para insertar gráfica.

Una vez que hayamos hecho las importaciones necesarias, procederemos a crear la ventana (a la que daremos el titulo de «Grafica insertada en Tkinter«) en la que insertaremos nuestra gráfica:

Creada la ventana, introduciremos los datos que generarán nuestra gráfica: Así definiremos la variable «fig«, en la cual, mediante la función «Figure«, definiremos las dimensiones que tendrá la gráfica. En este punto también definiremos una variable («t«) en la que especificaremos el rango numérico de la misma (que estará entre 0 y 3). Tras ello añadiremos el «subplot» en el que definiremos la expresión matemática que vamos a representar graficamente, usando el rango especificado en «t» y dibujaremos la gráfica con «canvas«:

Lo siguiente que haremos será añadir una barra de herramientas de «matplotlib» que nos permitirá (entre otras cosas) guardar nuestra gráfica, Lo cual haremos a través de la variable «toolbar» y el método «update«:

Una vez que tenemos creada nuestra gráfica dentro de una ventana creada con «tkinter«, como ejercicio, vamos a incorporar un botón, de modo que al clikar en el, cierre la misma:

Como se ve en la imagen, lo primero que haremos será definir la función encargada de cerrar la ventana que contiene nuestra gráfica (a dicha función le damos el nombre de «cerrar«). Tras lo cual, procederemos a crear dicho botón (con «button«) que llevará el texto «cerrar» («text=»cerrar«) y que al hacer clik en el, se llamará a la función «cerrar» («command=cerrar«) previamente definida, la cuál, primero finalizará el ciclo de ejecución del programa (mediante «.quit()«) para a continuación cerrarlo con «.destroy()«.

Hecho todo ello, simplemente nos restará usar el método «mainloop» (escribiendo «tkinter.mainloop()«), con ello, la ventana permanezca abierta en tanto no la cerremos:

Si ahora ejecutamos nuestro programa, obtendremos la siguiente ventana, que podremos cerrar dándole al botón «cerrar» que hemos ubicado debajo de la gráfica («side=tkinter.BOTTOM«):

El ejemplo aquí expuesto, podéis verlo en el siguiente enlace a github:

https://github.com/antonioam82/ejercicios-python/blob/master/inserta_grafica.py

Saludos.

CONCEPTO DE «COLA» Y SU IMPLEMENTACIÓN EN PYTHON.

Les saluda Antonio Alfonso Martínez, quién les da la bienvenida, una semana más, a «El Programador Chapuzas». Hace un tiempo estuvimos hablando de las «pilas» y de la forma de implementar esa estructura de datos en python. Pues bien, hoy vamos a hacer lo mismo con otra estructura importante : Las «colas«.

Para empezar, diremos que una «cola» (también llamadas «fila«) consiste en una estructura en la que los datos que la componen, se van añadiendo por un extremo de la cola, para después ser devueltos por el otro extremo de la misma, haciéndola avanzar (sírvanos como ejemplo de la vida real, el de la cola de clientes de un centro comercial) . Se trata de una estructura del tipo «FIFO«, del inglés «first in, first out» («primero en entrar, primero en salir»):


Esquema simplificado de una cola, en el que se ven las dos acciones principales: «encolar» y «desencolar».

Se trata de una estructura en la que solo podremos acceder al primer y último elemento de la cola, cuyos datos o procesos se irán almacenando para su posterior procesamiento o ejecución.

IMPLEMENTACIÓN EN PYTHON.

A continuación pasaremos a implementar esta estructura en python, teniendo en cuenta las funciones básicas que hay que plasmar:

ENCOLAR: Consiste en la adición de un nuevo elemento al final de la cola.

DESENCOLAR: Consiste en sacar un elemento ubicado en la cabecera de la cola.

Uno de los primeros procedimientos para llevar a cabo esta implementación es el empleo de listas como colas, en la que las funciones de «encolar» y «desencolar» sean llevadas a cabo por los métodos «insert()» y «pop()» respectivamente. De este modo, podemos crear una lista («lista«) a la que se irán añadiendo los distintos elementos (mediante «insert()«), de nuestra cola:

Como se ve en la imagen, hemos realizado la operación de adición de los elementos 1 y 2, haciendo uso del método «insert()» en el que hemos especificado, tanto la posición en la que queremos que se haga la inserción (posición 0 de la lista) como el elemento que queremos insertar. Por su parte, para emular la acción «desencolar» utilizaremos el método «pop()«, que devolverá el último elemento por la derecha:

De este modo, tenemos un sistema para emular el funcionamiento de las colas en python. Sin embargo, este sistema, basado en el uso del método «insert()» para reproducir la acción de «encolado» puede resultar demasiado costoso, en términos de tiempos de ejecución: Por ello, existe en python un módulo (llamado «deque«) especialmente diseñado para trabajar con filas y «colas«, con el que obtendremos mejores resultados, en términos de eficiencia. De modo que si repetimos el ejemplo anterior haciendo uso de dicho módulo:

En este caso, lo que hemos ha sido crear nuestra «fila» haciendo uso de dicho módulo (mediante «fila=deque()«) para a continuación, añadirle los distintos elementos mediante el método «append()» que ya conocemos. A su vez, la operación de «desencolar» la efectuaremos con «popleft()» para eliminar el último valor, por la izquierda. Con esto emulamos el funcionamiento de una cola en la los elementos se irán añadiendo a la cola, por la derecha (con «append()«) y eliminando por la izquierda con «popleft()«. No obstante, podemos invertir el sentido del «movimiento» de los datos a lo largo de la «cola/fila«, sustituyendo «append()» por «appendleft()» (para el añadido) y «popleft()» por «pop()» (para eliminar):

Con ello, tendríamos el modo de implementar esta estructura («colas«) en python. Para ello, podemos crear un «.py» que contenga una clase («Cola«), la cual, efectuará las acciones de «encolar» y «desencolar» a través dos métodos con el mismo nombre. A su vez, le incorporaremos 2 métodos más:»esta_vacia()«, que verificará si la cola a la que se aplica no contiene ningún elemento, de modo que la acción de «desencolar» solo se pueda ejecutar si no se da tal circunstancia y «muestra_cola» que mostrará el estado actual de la misma en cada momento:

Si ejecutamos el programa y lo aplicamos a una cola a la que llamaremos «fila», podremos llevar a cabo las distintas operaciones sobre esta que hemos definido en nuestra clase «Cola»:

Ejecución de la clase «Cola».

Podéis ver este ejemplo en el siguiente enlace a github:

https://github.com/antonioam82/ejercicios-python/blob/master/ejemplo_cola.py

Saludos.

DOS FORMAS DE CREAR UN CONVERSOR HEXADECIMAL-BINARIO, EN PYTHON.

Hola una vez más, les saluda Antonio Alfonso Martínez en una nueva entrega de «El Programador Chapuzas», en una ocasión en la que vamos a crear un sencillo programa para traducir un número escrito en el sistema hexadecimal al sistema binario.

Antes de emprender la creación, en python, de nuestro traductor hexadecimal-binario, debemos conocer el procedimiento «manual» para realizar tal conversión. En realidad se trata de un sistema bien sencillo que podéis ver en el siguiente video:

Conocido el procedimiento, estaremos en condiciones para implementarlo en python: En este punto vamos a exponer 2 formas distintas de hacerlo: Una «larga» mediante el uso de una lista, y otra «corta» en la que haremos uso de un diccionario:

MÉTODO LARGO (MEDIANTE LISTA)

Como se ve en el vídeo, el sistema hexadecimal (que usaremos como partida para hacer la conversión a binario) se compone de los caracteres 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E y F. Por lo que empezaremos, para nuestro programa, creando una lista (de nombre «lista_hex«) que contendrá dichos caracteres, dispuestos en ese orden:

Utilizamos una lista, en vez de un diccionario, debido al hecho de que el valor binario asociado a cada valor hexadecimal, se corresponde perfectamente con el valor binario de su correspondiente indice dentro de la lista «lista_hex«. Una vez creada la lista con los posibles valores hexadecimales, crearemos el «input» (al que llamaremos «hexa«) para la introducción del valor hexadecimal a convertir a binario. En este punto, también crearemos la lista «binario» en donde se irá almacenando el valor binario de cada uno de los caracteres hexadecimales (cuya unión constituirá el valor binario final):

Hecho esto, lo que vamos a hacer, es que nuestro programa recorra cada uno de los elementos almacenados en la variable «hexa» (es decir, cada uno de los valores que componen el número hexadecimal introducidos por el usuario) mediante una variable «i«, comprobando, primero, que dicho valor o caracter («i«), se encuentra entre los valores de «lista_hex» (con «if i in lista_hex:«), de modo que de encontrarse en dicha lista, proceder a realizar las ulteriores operaciones:

Una vez que el programa verifica que el valor actual de «i» se encuentra comprendido en «lista_hex«, procederá a extraer su correspondiente indice dentro de «lista_hex» mediante el método «.index()«, (almacenándolo en la variable «indice») a calcular (con la función «bin«) el valor binario de dicho indice. Tal cálculo devolverá una expresión del tipo «0b100» en donde «0b» representa la secuencia infinita de ceros que hay a la izquierda del primer 1. No obstante este formato no nos sirve para constituir el valor binario final, con lo que tendremos que proceder a eliminar del valor binario esos dos caracteres, mediante el método «.lstrip()» al string resultante de tal operación le daremos el nombre de «num_binar«.

Hecho ello, el valor binario correspondiente al valor actual de «i» (recordemos que todas estas operaciones las estamos realizando para cada uno de los caracteres de «hexa«) será un binario que empezará por su primer 1. No obstante, recordemos que cada uno de los valores binarios que compondrá el valor final, se tienen que componer de 4 dígitos, con lo que haremos uso de 2 nuevas variables:

La primera de ellas es «longi» la cual será igual al número de dígitos/caracteres que le quedan a «num_binar» (el string originado en el paso anterior) para alcanzar el valor de 4, que calculamos con «abs(len(num_binar)-4«, (usamos «abs» para evitar que se generen valores negativos). La otra variable es «n» que representará la cadena que añadiremos al principio del valor binario correspondiente a «i«, que será igual al string «0» repetido tantas veces como indique el valor «longi» calculado antes («n=»0″*longi«). A dicho «n» le sumaremos el string representado por «num_binar«. Suma a a que daremos el nombre de «n_cadena» («n_cadena=n+num_binar«) y que será la que, con la función «append» añadiremos a la lista «binario» («binario.append(n_cadena)«, que creamos antes de iniciar el ciclo.

Recordemos que la ejecución de esta serie de operaciones la hemos condicionado al hecho de que el valor actual de «i» se encontrara comprendido en «lista_hex«. No obstante, también podemos hacer que nuestro programa haga algo, en el caso contrario, como puede ser el imprimir un mensaje indicando que cierto caracter no se encuentra entre los hexadecimales. Ello lo haremos con un «else«:

Una vez creada la lista con los valores binarios formateados, para cada caracter de «hexa«, lo único que nos queda es unir (ya fuera del ciclo «for«) sus elementos (usando el método «.join()» y usando el espacio («») como criterio de unión. Tal valor final recibirá el nombre de «binario_final» y que será el que mostraremos como resultado final, mediante «print«:

Puesto que hemos enmarcado el programa en un «while«, haremos que la ejecución del mismo se repita en tanto que el usuario conteste no (con «n«) a la pregunta de si quiere continuar con la ejecución del mismo:

Conversor hexadecimal-binario (método largo).

Y con ello tendríamos creado nuestro conversor hexadecimal-binario:

MÉTODO CORTO (DICCIONARIO).

 Este proceso que acabamos de ver, se puede ver ampliamente simplificado haciendo uso de un diccionario (al que llamaremos «dic_hex«) en el que los pares de valores serán el string de cada posible valor hexadecimal y su correspondiente valor binario:

Correspondencia hexadecimal-binario.

Una vez creado el diccionario (poniendo cuidado en no equivocarnos en la correspondencia hexadecimal-binario), haremos que nuestro programa vaya recorriendo cada uno de los valores del input «hexa» (igual que como hacíamos en el primer procedimiento) verificando si tal caracter/valor se encuentra en el diccionario «dic_hexa«:

Una vez verificado el hecho de que el valor actual de «i» se encuentra en nuestro diccionario, lo único que tendremos que hacer es añadir a la lista «binario» (creada con anterioridad), mediante «append«, el par correspondiente al valor de «i» dentro del diccionario (es decir, su correspondiente binario) escribiendo «binario.append(dic_hex[i])«:

Como se puede ver, el empleo de un diccionario, nos ha sido de gran ayuda en la medida que nos simplifica mucho las operaciones ha realizar para cada valor del input «hex«. Por otra parte, aquí también hemos contemplado lo que ha de hacer nuestro programa para el caso de que el valor actual de «i» no se encontrara dentro de (en este caso) nuestro diccionario.

Finalmente, una vez que esté completada la lista «binario«, se procederá a unir sus elementos, siguiendo el mismo sistema que vimos en el primer supuesto:

Conversor hexadecimal-binario (método corto).

Y con ello tendríamos un ejemplo de la ventaja de contar con una estructura de datos como es la de los diccionarios.

En los enlaces siguientes, tenéis los dos métodos explicados en este artículo:

https://github.com/antonioam82/ejercicios-python/blob/master/hexa_bin.py

https://github.com/antonioam82/ejercicios-python/blob/master/hexabin.py

Saludos.

CONCEPTO DE «PILA» Y SU IMPLEMENTACIÓN EN PYTHON.

Bienvenidos, una vez más, a «El Programador Chapuzas», mi nombre es Antonio Alfonso Martínez, y en el presente artículo voy a hablar del concepto de «pila» y de su posible implementación adaptada al lenguaje de programación python.

Para empezar, diremos que una pila consiste en una estructura en las que los datos a manejar se almacenan de forma ordenada, en una lista, de tal modo que puedan, en un determinado momento, ser recuperados por el programa, para trabajar sobre ellos, siendo el modo de acceso a dichos datos del tipo «LIFO» (iniciales en inglés de «último en entrar, primero en salir«), lo cual, ilustra el hecho de que en este tipo de estructura, el dato que se saca, será siempre el último que se haya introducido.

El manejo de los datos implicados, se lleva a cabo a través de dos acciones principales: El apilamiento, mediante el cual, se añaden nuevos elementos (o datos) a la pila, y el desapilamiento, mediante el cual se realiza la operación inversa consistente en sacar el último elemento añadido de la pila. A su vez, hay que recordar que, en cada acción solo se podrá acceder al últimos elementos añadido (ubicado en el tope de la pila) de modo que su retirada, permitirá acceder al elementos anterior que pasará a ser el nuevo elemento ubicado en el tope.

A continuación, se muestra una representación esquemática de una pila:

Representación de una pila con un tope de 3 elementos y las 2 principales acciones que pueden realizarse sobre la misma: apilar y desapilar.

Se trata esta, de una estructura ampliamente utilizada en informática, dada su gran simplicidad y versatilidad. De ese modo, algunas de las aplicaciones de esta estructura serían: La evaluación de expresiones en «notación postfija» («Notación Polaca Invertida») que en su momento empleamos para crear una calculadora en un artículo al que me remito al final del presente,
Reconocedores sintácticos de lenguajes independientes del contexto o la implementación de recursividad.

IMPLEMENTACIÓN EN PYTHON.

A continuación, nos disponemos a realizar un sencillo ejemplo de implementación de esta estructura en el lenguaje python. Para ello, crearemos una clase, de nombre «Pila«, la cual, guardaremos en un archivo de nombre «ejemplo_pila.py«. Aquí, lo primero que hacemos es crear el constructor (con «def __ init__(self)«) el cual creará la lista «items«, la cual albergará los elementos de nuestra pila:

La lista «items» hará el papel de la pila contenedora.

Una vez que tenemos creada la lista, pasaremos a incluir los métodos que realizarán las acciones principales de la pila. Así, el primero que incluiremos será el método «.apilar()» el cual, llevará a cabo la acción de añadir nuevos elementos a nuestra pila, acción la cual, en python, reproduciremos mediante la función «append()» tomando como argumento, la variable «dato» (que no es otra cosa que el dato o elemento a añadir):

La función «append()» añadirá elementos a nuestra pila.

La otra acción que realiza la pila (la retirada de elementos de la misma) podemos reproducirla en python, mediante la función «.pop()» la cual, nos devuelve el último elemento de una lista. Así, incluiremos dicha función en un nuevo método al que llamaremos «desapilar«:

Por su parte, la función «.pop()» devolverá el último elemento introducido en la pila.

Como se puede ver, lo primero que va a hacer este método es verificar, mediante el método «esta_vacia()» (que pasaremos a definir a continuación) si la lista se encuentra vacía (en cuyo caso no devolverá ninguna acción) o si contiene 1 o más elementos (en cuyo caso devolverá el último de ellos (sacándolo de la pila) mediante la función «.pop()«).

Como ya hemos señalado, para saber si se puede o no desapilar, necesitamos hacer la verificación de «esta_vacia()«, por lo tanto pararemos a definir dicho método a continuación:

Como se ve, este método verificará si la pila esta o no vacía, en función a la longitud actual de la lista «items» de modo que si la longitud de esta es de 0 («if len(self.items)==0:«) se devolverá el valor booleano «True«, permitiendo al método «desapilar«, la acción de extraer el último elemento ingresado en la pila (mediante la función «.pop()«). De no darse dicha condición, devolverá el valor «False«, impidiendo la referida acción de extracción de la pila.

Finalmente, para controlar el estado interno de nuestra pila, incluiremos un método (al que daremos el nombre de «ver_pila«) que nos permita ver el contenido, en cada momento de la pila, lo que haremos mediante la conocida función «print«:

Y con ello, tendríamos creada nuestra pila en python. De modo que ahora podemos aplicarla a la variable que queramos:

Aplicación de la clase «Pila()» sobre una hipotética variable, de nombre «p1».

Podéis ver este ejemplo de implementación de la pila, en el siguiente enlace a github:

https://github.com/antonioam82/ejercicios-python/blob/master/ejemplo_pila.py

En lo referente a la calculadora «RNP» a la que hago alusión en este artículo, podéis leer su correspondiente artículo en el siguiente link:

https://programacionpython80889555.wordpress.com/2018/12/24/calculadora-rpn-con-interfaz-grafica-con-python-y-tkinter/?fbclid=IwAR3b4gOCINVbIExrzIvsqNdeJVjJuNWqHpWjUXu9Aj4l6LTQF7GHDV_TuGw

Saludos.