BitBite Python #3: Aula silenciosa en ausencia de profesores

Programa para el control de las aulas en ausencia de profesores.

Técnicas tratadas:

– Bucle while controlado por centinela
– Uso de diccionarios como estructura de datos flexible.
– Comprobación de si una clave determinada figura en un diccionario
– Modificación de los valores de un diccionario
Iteración sobre todos los elementos (claves – valores) de un diccionario

Nueva entrega de la serie BitBite Python, complemento práctico de los artículos del blog, en la que se desarrollan pequeños programas completos en Python empleando técnicas ya descritas en las secciones teóricas.

Hemos dedicado los últimos artículos a presentar una de las estructuras más poderosas y flexibles de Python: los diccionarios. Hoy mostraremos un ejemplo de utilización básico.

Para entender el problema a resolver, deja que te ponga primero en antecedentes:

Tengo un recuerdo nítido de mi infancia, en el colegio, cuando cursaba 2º o 3º de EGB. Era, por entonces, muy pequeño…

En determinadas ocasiones, si el profesor debía abandonar la clase para atender alguna gestión externa, encargaba a algún alumno (normalmente, el pelota de turno) para que se ocupase de mantener el silencio en el aula. Recuerdo que uno de esos días dejó un claro mensaje: «a quien abra la boca lo apuntas en la pizarra».

Eran tiempos en los que algunos profesores ejercían y demostraban su autoridad a base de tortazos. Todos sabíamos que aquellos cuyos nombres figurasen en la pizarra recibirían una o varias bofetadas, dependiendo de la magnitud de su falta.

Aunque, por lo general, la dureza de los castigos lograba que nos mantuviésemos callados, siempre había valientes que desafiaban a la autoridad. No eran buenos estudiantes, pero todos los respetábamos y, en cierto modo, temíamos.

Ese día quise provocar al pelotilla que vigilaba la clase y abrí la boca. Simplemente la abrí, de ella no salió ningún sonido. Pero el muy tonto me apuntó en la pizarra, tomándose al pie de la letra las instrucciones del profesor.

Naturalmente, cuando regresó el maestro recibí la bofetada de rigor. Creo que fue mi primera bofetada y lloré por la injusticia cometida. De nada me sirvió alegar que no habia pronunciado ni pío.

Ahí estaba mi nombre en la pizarra, injustamente entre los temerarios valientes:

Diego | | | |

Luis | |

Javier |

Cada barra vertical indicaba el número de veces que el alumno había infringido la regla. Si a mí me dolió, imagínate cómo le quedó la cara a Diego.

Si trasladamos esa escena unas cuantas décadas más adelante, quizás el pelota de turno tuviese delante un ordenador portátil o un Smartphone con Python instalado y podría improvisar unas sencillas líneas de código para acometer la tarea impuesta en vez de utilizar la tiza y la pizarra.

Estudiemos cómo podríamos resolver el problema…

Nos haría falta algún tipo de registro en el que anotar la misma información que escribiríamos en la pizarra: un nombre y el número de faltas cometidas.

Son dos campos de naturaleza distinta íntimamente asociados. Podemos pensar en un diccionario, con clave (única e irrepetible) el nombre del osado que se atreve a hablar y como valor el número de veces que lo hace.

Vamos a crear, entonces, un diccionario vacío que iremos rellenando conforme alguien hable. Eso es algo tan sencillo como esto:

bocazas = {}

El programa nos pregunta, por primera vez, quién ha hablado:

bocaza = input('Introduce el nombre del bocaza [0 si vuelve el profe]:')

Esto lo volverá a preguntar, una y otra vez, hasta que el profesor regrese. Necesitamos un modo de indicar al programa cuando ha ocurrido esa situación y hemos decidido que sea mediante la introducción de un 0.

Este tipo de bucles se denominan controlados por centinela. Se procesa todan las entradas hasta que llega ese valor especial, el centinela, que indica el final del ciclo.

He aquí el bucle al completo:

while bocaza != '0':
    if bocaza in bocazas:
        bocazas[bocaza] = bocazas[bocaza] + 1
    else:
        bocazas[bocaza] = 1
    bocaza = input('Introduce el nombre del bocaza [0 si vuelve el profe]:')

Observa la detección del centinela. El ciclo se repetirá mientras la variable bocaza, empleada para registrar el nombre de quien abra la boca, tenga un valor distinto de '0'. Escribo el cero entre comillas, pues la función input() devuelve strings aunque aparentemente estemos introduciendo números.

El funcionamiento del bucle es sencillo: comenzamos comprobando si el alumno ya ha incurrido en falta, en cuyo caso incrementamos en una unidad su número. Si no tenía antecedentes previos, creamos la clave en el diccionario con valor inicial uno.

No te líes con los nombres: bocazas es el diccionario y bocaza, en singular, el nombre del alumno (que actúa como clave del diccionario).

Finalmente, una vez ha sido fichado el infractor, el bucle vuelve a preguntar de nuevo por el siguiente charlatán. Y así sucesivamente hasta que el profesor regrese a la clase (momento en el cual se introducirá un cero en vez del nombre de una alumno real).

Llegado este punto, el pelota está a punto de mostrar satisfecho al profesor el resultado de su vigilancia:

print('LISTADO DE ALUMNOS QUE HAN ABIERTO LA BOCA')

for hablador, veces in bocazas.items():
    print(hablador, '-->', veces)

Nos interesa el bucle for: observa el uso del método items(), sobre el diccionario para crearnos un objeto compuesto de pares clave-valor (alumno-faltas) sobre el que podamos iterar. La variable hablador toma, uno a uno, el nombre de cada alumno, mientras que la variable veces captura el valor asociado a ese alumno en concreto.

Si hay algo que no comprendas en todo este proceso, te recomiendo que te leas los últimos artículos de la serie Python, en los que se detalla el uso de estas técnicas.

Este es, finalmente, nuestro listado completo:

# aulasilenciosa.py

# Programa para el control de aulas en ausencia de profesor
# El Club del Autodidacta

bocazas = {}

bocaza = input('Introduce el nombre del bocaza [0 si vuelve el profe]:')

while bocaza != '0':
    if bocaza in bocazas:
        bocazas[bocaza] = bocazas[bocaza] + 1
    else:
        bocazas[bocaza] = 1
    bocaza = input('Introduce el nombre del bocaza [0 si vuelve el profe]:')

#Ha regresado el profesor: es hora de delatar a los bocazas
# y que reciban su justo castigo

print() #Escribe una línea en blanco
print('LISTADO DE ALUMNOS QUE HAN ABIERTO LA BOCA')

for hablador, veces in bocazas.items():
    print(hablador, '-->', veces)

Interactuemos con él y veamos cómo trabaja:

Introduce el nombre del bocaza [0 si vuelve el profe]:Luis
Introduce el nombre del bocaza [0 si vuelve el profe]:Javier
Introduce el nombre del bocaza [0 si vuelve el profe]:Diego
Introduce el nombre del bocaza [0 si vuelve el profe]:Luis
Introduce el nombre del bocaza [0 si vuelve el profe]:Diego
Introduce el nombre del bocaza [0 si vuelve el profe]:Diego
Introduce el nombre del bocaza [0 si vuelve el profe]:Diego
Introduce el nombre del bocaza [0 si vuelve el profe]:0

LISTADO DE ALUMNOS QUE HAN ABIERTO LA BOCA
Luis --> 2
Javier --> 1
Diego --> 4

Tan sólo falta la ejecución de la sentencia. Por suerte para mí, si el pelota ya tiene un Smartphone en el que ejecutar este script, eso significa que estamos en tiempos donde los profesores ya no pegan bofetadas.

Por ahí me voy a librar.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2012/08/bitbite-python-3-aula-silenciosa-en-ausencia-de-profesores/


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta

Python: Recorriendo un diccionario de principio a fin

Objetivo: aprender a recorrer con un bucle for las claves, los valores o ambos de un diccionario en Python.

En numerosas ocasiones necesitaremos iterar a través de un diccionario mediante un bucle for. Voy a mostrarte lo sencillo que es y, para eso, te presentaré tres nuevos métodos que debes incorporar en tu kit de herramientas. Si has aterrizado en este artículo de modo casual y es la primera vez que te expones a los diccionarios en Python, te recomiendo que consultes el índice que figura en el menú o al final del artículo y estudies los artículos previos, que introducen los diccionarios desde cero.

Echa las manos al intérprete interactivo y genera un diccionario de pruebas:

>>> macedonia = {'plátano':'amarillo', 'fresa':'roja'}

Imagina que quieres trabajar con las claves de ese diccionario. ¿Cómo las obtenemos?

Empleando el método keys():

>>> frutas = macedonia.keys()
>>> frutas
dict_keys(['fresa', 'plátano'])

Si observas frutas, encontrarás las claves del diccionario, pero se trata de un objeto especial, claves de diccionario. Deja que te lo explique:

Lo que has obtenido es una vista del diccionario. Es como si observaras un objeto, el diccionario, desde una perspectiva diferente que sólo te permitiera apreciar determinadas características.

Hay dos cosas particularmente importantes en las vistas.

La primera es que lo que estás viendo a través de ellas es el objeto real. Si modificamos el diccionario, la vista se actualizará dinámicamente. Obśervalo.

Vamos a agregar un nuevo par clave-valor al diccionario y veamos qué sucede con la vista:

>>> macedonia['manzana'] = 'verde'
>>> macedonia
{'fresa': 'roja', 'plátano': 'amarillo', 'manzana': 'verde'}

¿Qué crees que contendrá ahora la vista frutas?

>>> frutas
dict_keys(['fresa', 'plátano', 'manzana'])

Como ves, se ha actualizado automáticamente sin necesidad de volvera a invocar al método?

La segunda particularidad de las vistas es que ya están preparadas para que puedas iterar sobre ellas:

>>> for fruta in frutas:
  print(fruta)

  
fresa
plátano
manzana

Tras lo cual hemos recuperado todas las claves del diccionario.

Si queremos iterar sobre los valores, en lugar de las claves, disponemos de otro método que genera una nueva vista:

>>> colores = macedonia.values()
>>> colores
dict_values(['roja', 'amarillo', 'verde'])

El método values() nos genera una vista sólo de valores sobre la que ya podemos iterar:

>>> for color in colores:
  print(color)

  
roja
amarillo
verde

Finalmente, ¿y si necesitamos iterar sobre las claves y sus correspondientes valores simultáneamente? La respuesta la encontrarás en el método items():

>>> elementos = macedonia.items()
>>> elementos
dict_items([('fresa', 'roja'), ('plátano', 'amarillo'), ('manzana', 'verde')])

Fíjate cómo iteramos ahora:

>>> for fruta, color in elementos:
  print(fruta, '-->', color)

  
fresa --> roja
plátano --> amarillo
manzana --> verde

Obviamente, no es necesaria la asignación previa de la vista. Tambień podrías haber escrito directamente esto:

>>> for fruta, color in macedonia.items():
  print(fruta, '-->', color)

Recuerda: las tres vistas son dinámicas y reflejan la situación actual del objeto.

Vamos a eliminar la fresa de la macedonia:

>>> del macedonia['fresa']
>>> macedonia
{'plátano': 'amarillo', 'manzana': 'verde'}

Y comprobemos nuestras preciosas vistas:

>>> macedonia
{'plátano': 'amarillo', 'manzana': 'verde'}
>>> frutas
dict_keys(['plátano', 'manzana'])
>>> colores
dict_values(['amarillo', 'verde'])
>>> elementos
dict_items([('plátano', 'amarillo'), ('manzana', 'verde')])

Pero, aunque el resultado sea el esperado, coincidirás conmigo que una macedonia sin fresas no es macedonia ni nada…

Javier Montero Gabarró


Python: Recorriendo un diccionario de principio a fin


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python – Consultando los valores de un diccionario

Objetivo: aprender diversas técnicas para consultar los valores de un diccionario en Python.

En esta tercera entrega dedicada a los diccionarios mostraremos cómo consultar los valores que contienen. Ya sabemos agregar o eliminar elementos (pares clave-valor), pero, ¿cómo realizamos consultas específicas?

El diccionario con el que trabajaremos hoy contiene información sobre unos personajes muy peculiares…

>>> gente = {'Pipi':'Calzaslargas', 'Bob':'Esponja',
   'Laura':'Ingalls', 'Sherlock':'Holmes'}

Comencemos determinando si nuestro diccionario contiene una clave concreta:

>>> 'Sherlock' in gente
True
>>> 'Dan' in gente
False

Hemos utilizado el operador in, un viejo conocido ya, para determinar la pertenencia. Podemos chequear, a su vez, la no pertenencia:

>>> 'Dan' not in gente
True

Es importante comprender que este uso sólo comprueba claves, pero no los valores correspondientes, como puedes apreciar en la siguiente instrucción:

>>> 'Esponja' in gente
False

En un próximo artículo aprenderemos métodos que nos permitirán obtener secuencias con las claves, los valores o con ambos, pero primero has de asegurarte de interiorizar bien esto.

Ya sabemos si una clave existe en un diccionario. Nuestra siguiente pregunta es: ¿cómo conocemos el valor que tiene asociado?

La forma más simple de extraer el valor de una determinada clave es utilizar la sintaxis siguiente:

diccionario[clave]

Consultemos qué valor tiene asignado la clave ‘Laura’:

>>> gente['Laura']
'Ingalls'

Si tratamos de consultar el valor de una clave inexistente tendríamos un serio problema:

>>> gente['Pedro']
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    gente['Pedro']
KeyError: 'Pedro'

Se produce un error y el programa se aborta. Más adelante, cuanto tratemos las excepciones, veremos el modo general que provee Python para controlar este tipo de errores, pero ahora veremos técnicas asociadas a los diccionarios para resolver este problema concreto.

Una forma obvia de gestionar este fallo sería realizar una comprobación de pertenencia antes de tratar de consultar el valor:

>>> if 'Pedro' in gente:
  print(gente['Pedro'])
else:
  print('Esta clave no existe')

  
Esta clave no existe

Pero disponemos de una manera más elegante. Deja que te presente el método get().

>>> gente.get('Laura')
'Ingalls'

Como ves, es lo mismo que haber hecho:

>>> gente['Laura']
'Ingalls'

Pero tiene una importante diferencia. Prueba ahora esto:

>>> gente.get('Pedro')

No devuelve nada, puesto que la clave no existe, pero, al menos, no provoca un error.

Y aún hay más: podemos indicar qué valor queremos que se devuelva para el caso en que la clave no exista:

diccionario.get(clave, valor_por_defecto)

>>> gente.get('Bugs', 'Esta clave no existe')
'Esta clave no existe'

Y, como decía un viejo amigo: That’s all folks!

Javier Montero Gabarró


Python – Consultando los valores de un diccionario


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Agregar y eliminar elementos de un diccionario

Objetivo: mostrar cómo agregar y eliminar elementos de un diccionario en Python.

En la anterior entrega explicamos el concepto de diccionario en Python y vimos el modo de crearlos. Hoy presentaremos dos técnicas básicas: la agregación y eliminación de elementos.

Comencemos con la creación de un par de diccionarios de ejemplo sobre los que practicaremos desde el intérprete interactivo:

>>> gazpacho = {}
>>> menda = {'Nombre':'Javier', 'Apellido':'Montero'}

El primero, gazpacho, es un simple diccionario vacío que utilizaremos para almacenar la receta del gazpacho; el otro, menda, recoge algunos datos sobre mi persona. Más adelante veremos que podemos crear estructuras de datos más complejas, basadas en los diccionarios, que podremos emplear para mantener una agenda de nuestros contactos personales y sin necesidad de recurrir a un gestor de bases de datos.

Para agregar un par clave-valor a un diccionario, recurrimos a la siguiente sintaxis:

diccionario[clave] = valor

Probémoslo con gazpacho:

>>> gazpacho['Aceite'] = '300 ml'

Verificamos que gazpacho, que antes estaba vacío, ahora contiene ese par:

>>> gazpacho
{'Aceite': '300 ml'}

Continuemos con la receta secreta:

>>> gazpacho['Vinagre'] = '100 ml'
>>> gazpacho['Pepino'] = 1
>>> gazpacho['Pimiento'] = 1

Veamos cómo evoluciona nuestra creación:

>>> gazpacho
{'Pimiento': 1, 'Aceite': '300 ml', 'Vinagre': '100 ml', 'Pepino': 1}

Observa la salida de esta última instrucción y recuerda lo que dijimos sobre el orden de los diccionarios: no son una estructura ordenada, aunque veremos formas de hacerlos más presentables si lo deseamos.

Añadamos nuevos elemendos al menda:

>>> menda['URL'] = 'http://www.elclubdelautodidacta.es'
>>> menda['Twitter'] = '@pradery'

tras lo cual,

>>> menda
{'URL': 'http://www.elclubdelautodidacta.es', 'Nombre': 'Javier', 'Twitter': '@pradery', 'Apellido': 'Montero'}

Las claves han de ser únicas. Si tratamos de agregar otra ya existente, simplemente el valor nuevo sustituirá al antiguo:

>>> gazpacho['Pimiento'] = 2
>>> menda['URL'] = 'http://elclubdelautodidacta.es/wp/'

Observa cómo los valores correspondientes son actualizados:

>>> gazpacho
{'Pimiento': 2, 'Aceite': '300 ml', 'Vinagre': '100 ml', 'Pepino': 1}
>>> menda
{'URL': 'http://elclubdelautodidacta.es/wp/', 'Nombre': 'Javier', 'Twitter': '@pradery', 'Apellido': 'Montero'}

Para borrar un par clave-valor de un diccionario disponemos de la sentencia del, que emplearemos del siguiente modo:

del diccionario[clave]

Por ejemplo:

>>> del gazpacho['Aceite']
>>> gazpacho
{'Pimiento': 2, 'Vinagre': '100 ml', 'Pepino': 1}

>>> del menda['URL']
>>> menda
{'Nombre': 'Javier', 'Twitter': '@pradery', 'Apellido': 'Montero'}

Con del podríamos cargarnos incluso el objeto completo:

>>> del gazpacho

A partir de este momento el gazpacho ha dejado de existir y ha pasado a mejor vida:

>>> gazpacho
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    gazpacho
NameError: name 'gazpacho' is not defined

Y con menda mejor no lo hago, no sea que traiga mala suerte…

Javier Montero Gabarró


Python: Agregar y eliminar elementos de un diccionario


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Introducción a los diccionarios

Objetivo: entender el concepto de diccionario en Python y aprender cómo se crean.

Tengo el placer de presentarte los diccionarios de Python, estructuras de datos fascinantes y tremendamente adictivas. Con frecuencia, cuando necesito resolver mediante programación alguna necesidad, me encuentro con que los diccionarios me vienen a la cabeza de un modo natural. Son objetos muy poderosos, como irás comprobando.

Ya sabes, en otro sentido, lo que es un diccionario, llevas toda tu vida manejándolos. Abre uno cualquiera por una página al azar y dime qué ves.

Un conjunto de términos y sus definiciones, no es más que eso. Un conjunto de claves (las palabras) y sus correspondientes valores (las definiciones).

Un diccionario en Python es, en esencia, lo mismo: una colección de pares formados por claves y definiciones.

Las claves no tienen que ser, necesariamente, palabras: puede servir cualquier tipo que sea inmutable, como los números o los strings. O incluso estructuras más complejas como las tuplas (que ya sabes que son inmutables, en oposición a las listas), pero con la condición de que los elementos que las componen sean también inmutables (por ejemplo, que dentro de una tupla no exista una lista). Más adelante comprenderemos el porqué de estas «manías» que tienen las claves de los diccionarios. Los valores, en cambio, no tienen estas restricciones y pueden ser de cualquier tipo.

Hay un concepto que diferencia a los diccionarios Python de los de papel de toda la vida. En estos, las palabras (claves) están ordenadas alfabéticamente, de la a a la z. Sin embargo, aunque muchas veces nos dará la sensación de lo contrario, no hay ordenación implícita en los elementos de un diccionario en Python. Veremos que existen métodos que nos permitirán, si lo necesitamos, poner orden en ese caos, pero hazte a la idea de que los diccionarios no son estructuras ordenadas. Si te gustaba la analogía con el diccionario de papel, imagínala como si hubieras recortado todos los pares término-definición y los hubieras metido en un saco, perdiendo así su orden natural.

Pongámonos manos a la obra ya. Vamos a crear un diccionario sencillo que nos sirva para asociar a cada uno de nuestros amigos con su fecha de cumpleaños. Por ejemplo:

'Marta': '25 de abril'
'José Luis' : '5 de diciembre'

En este ejemplo, todas las claves y los valores son de tipo string, por eso los he incluido entre comillas (da igual que sean simples o dobles), pero no tendría por qué haber sido así. Nada nos impediría, tampoco, introducir un par clave-valor así:

456 : '14 de mayo'

Es decir, ni las claves ni los valores tienen por qué mantener homogeneidad en sus tipos. Naturalmente, no tendría sentido en nuestro problema particular, pero sería un par válido.

Fíjate cómo hemos separado las claves de los valores empleando dos puntos.

Para crear el diccionario, separamos cada par mediante comas y rodeamos todo el conjunto entre llaves:

>>> cumpleaños = {'Marta': '25 de abril', 'José Luis' : '5 de diciembre'}

Comprobemos el tipo de este objeto:

>>> type(cumpleaños)
<class 'dict'>

Y su valor:

>>> cumpleaños
{'Marta': '25 de abril', 'José Luis': '5 de diciembre'}

Una regla de oro que cumplen los diccionarios es que las claves han de ser únicas. Si tratas de agregar un elemento con la misma clave que otro ya existente, simplemente el valor nuevo sobreescribirá al antiguo.

Para crear un diccionario vacío procedemos del siguiente modo:

>>> dicci = {}   # Un simple par de llaves sin nada dentro
>>> type(dicci)
<class 'dict'>

Ya sabemos crear diccionarios, vacíos o con pares clave-valor dentro. Próximamente aprenderemos a agregar o eliminar datos de estas estructuras ya creadas.

Javier Montero Gabarró


Python: Introducción a los diccionarios


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Conjuntos inmutables con frozenset

Objetivo: presentar el tipo frozenset para la implementación de conjuntos inmutables.

Al igual que las listas encuentran en las tuplas su versión inmutable, los conjuntos, que como vimos quedaban representados por el tipo set, hallan su inalterabilidad a través del tipo frozenset.

Podríamos traducir frozenset por algo así como conjunto congelado, término que muestra claramente su carácter estático. Podemos pensar en un frozenset como en un set en el que no podemos modificar su composición una vez creado.

Veamos cómo creamos un frozenset:

>>> c1 = frozenset({'pradera', 2, 'pimiento'})
>>> c1
frozenset({'pimiento', 2, 'pradera'})

Presta mucha atención: empleamos el constructor frozenset, facilitando, como argumento, entre paréntesis, un conjunto definido explicitamente.

En general, el argumento no tiene por qué ser un conjunto, sino que sirve cualquier tipo de objeto iterable, como una lista. Más adelante hablaremos formalmente de qué significa exactamente eso de ser iterable, pero por el momento quédate con que un iterable es cualquier objeto que puede ser recorrido de principio a fin dentro de un bucle for.

Por lo tanto, la definición anterior también podrías haberla hecho así:

>>> c1 = frozenset(['pradera', 2, 'pimiento'])
>>> c1
frozenset({'pimiento', 2, 'pradera'})

El resultado, como ves, es el mismo empleando corchetes (listas) que llaves (conjuntos). O incluso si facilitas unta tupla como argumento:

>>> c1 = frozenset(('pradera', 2, 'pimiento'))
>>> c1
frozenset({'pimiento', 2, 'pradera'})

Date cuenta de que, aunque estemos facilitando varios datos a través de un conjunto, lista o tupla, en realidad dentro de frozenset hay un único argumento. El siguiente código sería erróneo:

>>> frozenset('pimiento', 2, 'pradera')
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    frozenset('pimiento', 2, 'pradera')
TypeError: frozenset expected at most 1 arguments, got 3

ya que hemos introducido tres argumentos y, como informa el código de error, cómo máximo admite uno.

En efecto: como máximo un argumento. O, lo que es lo mismo, uno o ninguno.

>>> c2 = frozenset()
>>> c2
frozenset()

Como vemos, cuando no facilitamos ningún argumento, creamos un frozenset vacío.

Las cadenas de caracteres también son iterables, pues pueden ser recorridas de principio a fin con un bucle for. Por lo tanto, también nos pueden servir para generar un frozenset:

>>> c3 = frozenset('pradera')
>>> c3
frozenset({'a', 'p', 'r', 'e', 'd'})

Observa qué ha pasado: se ha descompuesto la cadena en sus caracteres individuales, eliminando las repeticiones. Esto es algo natural, ya que los conjuntos no pueden tener elementos repetidos, como vimos en los últimos artículos.

Esta manera de crear un frozenset a través de su constructor también es válida para el tipo set.

>>> c4 = set('la casa de la pradera')
>>> c4
{'a', ' ', 'c', 'e', 'd', 'l', 'p', 's', 'r'}

Una forma muy rápida de crear un conjunto a partir de un string, como podemos ver.

Set y frozenset son hermanos, por lo que puedes emplear muchos de los operadores y métodos que ya aprediste con set. Realizemos, por ejemplo, una unión:

>>> c1 = frozenset({1, 2, 3})
>>> c2 = frozenset({4, 5, 6})
>>> c1 | c2
frozenset({1, 2, 3, 4, 5, 6})

En cambio, ya que los frozenset son inmutables y no podemos modificarlos, no aceptan aquellos métodos que traten de alterar su composición. Intentemos agregar un nuevo elemento a c1 y veamos qué sucede:

>>> c1.add(5)
Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    c1.add(5)
AttributeError: 'frozenset' object has no attribute 'add'

El mensaje es rotundo: el objeto frozenset no tiene método add.

¿Por qué usar un frozenset en lugar de un set? Una razón importante puede ser para garantizar que nuestro código no alterará una estructura de datos que no debamos modificar. Además, como veremos en breve cuando comencemos con los diccionarios, las claves de estos han de ser de un tipo inmutable, como son los strings, tuplas o frozensets, pero no servirían ni las listas ni los sets, que son modificables.

El tema de la mutabilidad en Python puede resultar un tanto misterioso si estás habituado a otros lenguajes de programación. Merecerá que se le dedique un artículo monográfico…

Javier Montero Gabarró


Python: Conjuntos inmutables con frozenset


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Subconjuntos – Conjuntos disjuntos

Objetivo: implementar los conceptos de subconjuntos y conjuntos disjuntos en Python.

Vamos a ir concluyendo el tema de los conjuntos, que tengo interés en presentar pronto otra de las superestructuras fabulosas de Python, los diccionarios.

La teoría nos dice que A es subconjunto de B cuando A está incluido en B, que es lo mismo que decir que B contiene a A.

Para implementar estos conceptos en Python, disponemos de los operadores de comparación habituales:

== igual
!= distinto
>  mayor
>= mayor o igual
<  menor
<= menor o igual

A es un subconjunto de B cuando todos los elementos de A están incluidos en B, relación que expresamos por

A <= B

que es equivalente a

B >= A

Puede interesarte también la inclusión estricta:

A < B, que es lo mismo que decir B > A

Practiquemos estos operadores con los siguientes conjuntos:

>>> c1 = {1, 2, 3}
>>> c2 = {1, 2, 3}
>>> c3 = {1, 2, 3, 4, 5, 6}
>>> c4 = {2, 4, 6}
>>> c5 = {1, 3, 5}

Observa que c1 y c2 son iguales, pues contienen los mismos elementos

>>> c1 == c2
True

pero c2 y c3 no lo son:

>>> c2 != c3
True

Sin embargo, c2 es un subconjunto de c3, pues todos los elementos de aquel están incluidos en este:

>>> c2 <= c3
True

A su vez, c1 es un subconjunto de c2, aunque sean iguales:

>>> c1 <= c2
True

Pero no lo sería en sentido estricto:

>>> c1 < c2
False

El concepto de subconjunto también está disponible como método:

>>> c1.issubset(c3)
True

que debe leerse como c1 es subconjunto de c3,

y es lo mismo que

c1 <= c3

También puedes expresarlo del siguiente modo:

>>> c3.issuperset(c1)
True

que debes leerlo como c3 es superconjunto de c1, que es lo mismo que decir que c3 contiene a c1:

c3 >= c1

Para finalizar, unas palabras sobre el concepto de conjuntos disjuntos. Sabemos que dos conjuntos son disjuntos cuando no tienen elementos en común, es decir, su intersección es el conjunto vacío.

En el artículo anterior tratamos la intersección, así que ya tenemos recursos para practicar esto sobre los conjuntos c4 y c5, que como puedes observar, son disjuntos:

>>> c4 & c5 == set()
True

Recuerda que set() simboliza el conjunto vacío, y no {}, que sería un diccionario vacío, como veremos muy pronto.

Pero esta instrucción podría prestarse a error fácilmente: el uso de set() o el orden de evaluación de los operadores.

¿Qué tal esta otra, más sencilla?

>>> c4.isdisjoint(c5)
True

Se acerca el final del repaso que le estamos dando a los conjuntos en Python. En la próxima entrega presentaremos el tipo frozenset, conjunto congelado, que es como el tipo set, pero inmutable.

Qué trascendente ha sonado esta última palabra; me está entrando hasta frío…

Javier Montero Gabarró


Python: Subconjuntos – Conjuntos disjuntos


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Unión, intersección y diferencia de conjuntos

Objetivo: aprender a realizar operaciones como la unión, intersección y diferencia de conjuntos en Python.

Continuamos nuestro repaso al tipo set en Python aprendiendo, por fin. a realizar las operaciones clásicas por antonomasia.

Definamos antes algunos conjuntos sobre los que practicar:

>>> c1 = {1, 2, 3, 4, 5, 6}
>>> c2 = {2, 4, 6, 8, 10}
>>> c3 = {1, 2, 3}
>>> c4 = {4, 5, 6}

Empecemos por la unión de dos conjuntos, definida como el conjunto de elementos que están en uno o en otro (o en ambos).

>>> c1 | c2
{1, 2, 3, 4, 5, 6, 8, 10}

Podemos incluir más de dos operandos:

>>> c1 | c2 | c3
{1, 2, 3, 4, 5, 6, 8, 10}

Y seguimos con la intersección: el conjunto de elementos que estan en ambos.

>>> c1 & c2
{2, 4, 6}

>>> c1 & c2 & c3 & c4
set()       # El conjunto vacío

Estos operadores también tienen variantes como métodos del objeto set. Observa su uso autoexplicativo:

>>> c1.union(c2)
{1, 2, 3, 4, 5, 6, 8, 10}

>>> c1.intersection(c2, c3)
{2}

La diferencia de dos conjuntos A y B, A – B, es el conjunto de elementos que están en A pero no en B. En Python se implementa con un operador de resta simple (-):

>>> c1 - c2
{1, 3, 5}

La unión exclusiva, también conocida como diferencia simétrica, es el conjunto de elementos que están en A o B, pero no en ambos:

>>> c1 ^ c2
{1, 3, 5, 8, 10}

Compara este resultado con la unión, calculada anteriormente.

También existe versión método para estos operadores:

>>> c1.difference(c2)
{1, 3, 5}

>>> c1.symmetric_difference(c2)
{1, 3, 5, 8, 10}

Más adelante conoceremos situaciones en las que será más interesante usar los métodos que los operadores, aunque ahora quizás te resulte redundante.

Aún nos quedan algunos métodos por conocer relacionados con los conjuntos, pero no dispongo de más tiempo por hoy, de modo que los dejaremos para la siguiente ocasión.

Para finalizar, un pequeño consejito: conoce bien las estructuras de datos y el tipo de operaciones que puedes realizar con ellas. Con frecuencia, resolver elegantemente un problema de programación no se reduce a otra cosa sino a elegir la estructura de datos más adecuada.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2012/07/python-union-interseccion-y-diferencia-de-conjuntos/


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python – Agregación y eliminación de elementos de un conjunto

Objetivo: aprender a agregar y eliminar elementos de un conjunto en Python.

Pongámonos al día. En Introducción a los conjuntos presentamos el tipo set para almacenar conjuntos. Aprendimos a crearlos, tanto un conjunto vacío, como con datos preexistentes. Vimos también cómo comprobar si un determinado elemento pertenece o no al conjunto, así como determinar la cardinalidad, es decir, el número de elementos en total.

Con estos conceptos claros, es momento de aprender a realizar otras operaciones básicas, como la agregación y eliminación de elementos a conjuntos ya existentes.

Comencemos creando un par de conjuntos sobre los que trabajaremos:

>>> c1 = set()     # El conjunto vacío
>>> c2 = {1, 2, 3, 4, 5, 6}

Para añadir elementos a un conjunto disponemos del método add.

Por ejemplo,

>>> c1.add('pimiento')
>>> c1
{'pimiento'}

Para agregar elementos a un conjunto hemos de hacerlo de uno en uno. Si intentaras meter varios de golpe se produciría una excepción.

>>> c1.add(5)
>>> c1
{'pimiento', 5}

Observa, tras esta última operación, que los elementos pueden ser de tipos variados dentro del mismo conjunto.

Fíjate en esta otra instrucción:

>>> c2.add((7, 8))

¿No hemos dicho que no se podía introducir más que un elemento cada vez?

En efecto, así es. Pero date cuenta de que no hemos introducido dos elementos, sino sólo uno: la tupla (1, 2). Observa los paréntesis.

>>> c2
{1, 2, 3, 4, 5, 6, (7, 8)}

Si no te fías, comprueba la cardinalidad:

>>> len(c2)
7

en lugar de 8.

Como vemos, agregar elementos a un conjunto es una labor simple. Borrarlos es igual de sencillo, pero nos ofrece más variedad de opciones.

Quizás no te guste tener que retirar elementos de un conjunto. Si prefieres, puedes dejar que Python se ocupe por ti de la difícil decisión empleando el método pop.

>>> c2.pop()
1

El método pop no sólo elmina un elemento, sino que además nos presenta cuál ha retirado del conjunto. No debe llevar argumentos.

>>> c2
{2, 3, 4, 5, 6, (7, 8)}

>>> c2.pop()
2
>>> c2
{3, 4, 5, 6, (7, 8)}

¿Adivinas cuál será el siguiente a extraer?

>>> c2.pop()
3

Pero no te confundas… Aunque podamos predecirlo fácilmente en este caso, considera mejor que Python te devolverá un valor arbitrario. Piensa que los elementos de un conjunto no tienen orden, aunque internamente Python pueda implementarlos de acuerdo a su propio criterio. Observa el siguiente ejemplo:

>>> c3 = {'luis', 'pedro', 'juan'}

Presta atención al orden en que han sido introducidos. Ahora observa cómo te muestra Python el conjunto:

>>> c3
{'luis', 'juan', 'pedro'}

No coincide con el orden de introducción. Ni siquiera están por orden alfabético.

Si ahora hago un pop sé que extraerá a ‘luis’, el elemento primero en ese orden peculiar, pero eso no es fácilmente deducible a partir de los datos iniciales.

>>> c3.pop()
'luis'

Lo dicho: considerara que el valor que extrae pop es completamente arbitrario.

¿Qué utilidad puede tener extraer un elemento arbitrario de un conjunto?

Imagínate que los tres amigos de antes, Luis, Pedro y Juan, han quedado a tomar unas cervezas. Llega el momento de rascarse el bolsillo y nadie parece decidirse a pagar. Mete a los tres en un conjunto y deja que Python decida…

Pero, aunque la elección es arbitraria, te recomiendo que no emplees pop si lo que de verdad buscas es aleatoriedad. Hay otras maneras más justas de hacerlo.

Para eliminar un elemento concreto de un conjunto, usa el método remove:

>>> c2.remove(5)
>>> c2
{4, 6, (7, 8)}

Pero ten mucho cuidado: si el elemento no existe te devolverá un error.

>>> c2.remove(2)
Traceback (most recent call last):
  File "<pyshell#58>", line 1, in <module>
    c2.remove(2)
KeyError: 2

Si no quieres correr ese riesgo, existe el método discard, que elimina un elemento sólo en el caso de que exista.

>>> c2.discard((7, 8))   # Eliminando la tupla (7,8)
>>> c2
{4, 6}

>>> c2.discard(2)
>>> c2
{4, 6}

Para hacer limpieza completa de un conjunto, sin remordimiento alguno, disponemos del método clear:

>>> c2.clear()
>>> c2
set()

Recuerda, por el artículo anterior, que el conjunto vacío se representa por set(), en vez de {}, que correspondería a un diccionario vacío.

Hemos colocado nuevas piezas sobre el puzzle. En el próximo artículo veremos cómo gestionar operaciones sobre conjuntos de toda la vida como la unión y la intersección.

Javier Montero Gabarró


Python – Agregación y eliminación de elementos de un conjunto


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python – Introducción a los conjuntos

Objetivo: aprender a crear conjuntos, colecciones de objetos no ordenados, y mostrar cómo determinar la pertenencia y cardinalidad.

Aprovechando que voy a hablar hoy de una estructura de datos no ordenada (en contraposición a las listas o tuplas, por ejemplo), he decidido abandonar la numeración secuencial también en los artículos sobre programación en Python (este debería ser el capítulo 35). Eso me dará más libertad a la hora de elegir los contenidos: comienzo dando capas sobre varios temas que posteriormente retomo. Gradualmente se van interconectando entre sí las distintas piezas del puzzle.

De hecho, ese el modo como aprendemos.

Piensa en los conjuntos como cuando estudiabas matemáticas de pequeño. ¿Recuerdas los famosos círculos, denominados diagramas de Venn, con elementos en su interior? ¿Recuerdas cuando solapábamos esos círculos y hablábamos de cosas como su intersección o unión?

Un conjunto no es más que eso: un conjunto de elementos. No hay un primero ni un segundo. No existe ordenación alguna en ellos: un elemento simplemente está o no está.

Python maneja dos tipos para tratar con conjuntos, en función de si necesitas modificar su contenido o no: set (mutable) y frozenset (inmutable). Hoy nos ocuparemos del primero.

Veamos cómo creamos un conjunto con ciertos elementos concretos:

>>> conjunto1 = {1, 'pimiento', 3, 5}

Esto es, para crear un conjunto, situamos entre llaves todos los elementos separados por comas. Observa como los elementos pueden ser de tipos distintos.

Podemos comprobar que conjunto1 es del tipo set:

>>> type(conjunto1)
<class 'set'>

Para crear un conjunto vacío puede ser tentador hacer algo como:

>>> conjunto2={}

Sin embargo, el resultado no sería el esperado:

>>> type(conjunto2)
<class 'dict'>

Se ha creado un diccionario, estructura que también se rodea entre llaves. Hablaremos de ellos muy pronto.

Para que conjunto2 sea un conjunto vacío debemos proceder del siguiente modo:

>>> conjunto2 = set()

Y ahora sí:

>>> type(conjunto2)
<class 'set'>

Los elementos de un conjunto sólo pueden figurar una vez en él. Observa este otro ejemplo, en el que pese a repetir el número 7 en la definición de conjunto3, sólo se nos muestra una vez:

>>> conjunto3 = {4, 7, 7, 1}
>>> conjunto3
{1, 4, 7}

Constata, a su vez, como el orden no es significativo.

Lo siguiente que debemos aprender es cómo saber si un determinado elemento pertenece a un conjunto o no. Disponemos para ello del operador in:

>>> 'pimiento' in conjunto1
True
>>> 4 in conjunto1
False

Potentísimo.

La no pertenencia se determina de modo parecido:

>>> 'pepino' not in conjunto1
True

Para finalizar este primer barniz sobre conjuntos, la función len(), que ya conoces para determinar la longitud de un string o el número de elementos de una lista, sirve también para conocer el cardinal de un conjunto, esto es, el número de elementos que lo componen.

>>> len(conjunto1)
4
>>> len(conjunto2)
0
>>> len(conjunto3)
3

El conjunto vacío, conjunto2, figura con cardinal cero, como es de esperar.

Suficiente. La próxima vez que hablemos sobre conjuntos te mostraré cómo agregar o retirar elementos de ellos.

>>> ecda = {'python', 'latex', 'armonía', 'mirc', 'musescore'}
>>> 'cocina' in ecda
False

Aunque todo se andará. Espera a ver si no publico mi peculiar receta de patatas bravas

Javier Montero Gabarró


Python – Introducción a los conjuntos


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies