Python: Aprendiendo a escribir

Objetivo: aprender el modo que tiene Python de escribir texto en un fichero.

Si te has leído el anterior artículo de esta serie, probablemente habrás intuido la temática del artículo hoy: la escritura en ficheros de texto.

Todo comenzó un día de octubre, cuando un nuevo y sofisticado ente entró en escena:

fichero = open('pruebas.txt')

Esta instrucción creaba un nuevo objeto, una abstracción del fichero de texto real en disco, pruebas.txt, que nos permitía realizar operaciones de lectura sobre él.

En realidad, ese comando no es más que una forma simplificada de:

fichero = open('pruebas.txt', 'rt')

O incluso:

fichero = open('pruebas.txt', 'r')

Las letras entrecomilladas, como segundo parámetro de la función open(), indican el modo en que se abrirá el fichero. La r (de read) y la t (de text) hacen referencia a que se trata de un fichero de texto y que sólo realizaremos operaciones de lectura, no estando, por lo tanto, permitida su modificación.

Cuando no se especifica el modo de apertura, se presupone la opción por defecto, que es precisamente esta: texto y lectura.

Hoy vamos a realizar la operación inversa: la escritura de ficheros de texto. Para ello presentaremos un nuevo modo: ‘w’, forma simplificada de ‘wt’.

Introduce la siguiente instrucción en un intérprete interactivo:

>>> fichero = open('prueba2.txt', 'w')

Lo primero que debes saber del modo ‘w’ es el efecto de esta operación: si el fichero indicado no existe, lo creará (naturalmente, vacío), y si ya existe lo sobreescribirá, perdiendo su contenido (y dejándolo, por lo tanto, vacío también).

El tipo de objeto es el mismo que en el ejemplo del artículo anterior:

>>> type(fichero)
<class '_io.TextIOWrapper'>

Con la particularidad de que las operaciones de lectura no están permitidas:

>>> fichero.read()
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    fichero.read()
io.UnsupportedOperation: not readable

El modo ‘w’, de write, nos permite escribir en ese fichero. El método estándar para realizar esto es write():

>>> fichero.write('Serie: La casa de la pradera\nAño: ni lo recuerdo, \
yo era pequeño\n\n¿La repondrán? ')
81

He facilitado, entre comillas, un string con el texto que quiero introducir. Lo podría haber hecho línea a línea, con llamadas a write() sucesivas, pero he optado por incluirlo todo en uno solo. Observa que, para separar una línea de la siguiente necesito hacer uso del carácter de escape \n.

La barra \ que he escrito al final de la primera línea es para decirle al intérprete que voy a continuar en la siguiente línea, de modo que quede más presentable el código. No forma parte del string.

El método write() devuelve un número con el total de caracteres que han sido escritos, 81 en este caso.

Las escrituras sucesivas continúan justo en el punto donde terminó la última:

>>> fichero.write('Quién sabe.')
11

Comprobemos es aspecto de nuestro archivo de texto final. Para ello, primero hay que cerrar el fichero, indicando que hemos dejado de trabajar con él, liberando la memoria ocupada y haciendo que se vuelque la información efectivamente en el disco:

>>> fichero.close()

Este es el contenido de prueba2.txt tras estas operaciones:

Serie: La casa de la pradera
Año: ni lo recuerdo, yo era pequeño

¿La repondrán? Quién sabe.

La escritura puede ser, desde luego, en cualquier parte del fichero, no necesariamente a continuación de la última operación. Podemos desplazarnos a cualquier punto empleando el método seek() que presentamos brevemente en el último artículo. Veremos esto a su debido momento.

Una operación frecuente en el trabajo con ficheros en Python consiste en volcar a un archivo de texto el contenido de una secuencia. Considera, por ejemplo, la siguiente lista:

>>> a = ['Litio\n', 'Sodio\n', 'Potasio\n']

Nuestra misión consistirá en crear un fichero de texto en el que figure cada elemento en una línea diferente.

Con lo explicado hasta el momento tenemos recursos suficientes para resolvere el problema: realizamos una iteración sobre la lista escribiendo, en cada pasada, el elemento correspondiente:

>>> fichero = open('prueba2.txt', 'w')  #El fichero antiguo se perderá
>>> for elemento in a:
  fichero.write(elemento)

  
6
6
8
>>> fichero.close()

Los tres números devueltos por el intérprete de comandos son, como hemos dicho, el número de caracteres escritos tras cada operación. En un programa independiente no aparecerían.

El fichero prueba2.txt tiene el contenido buscado:

Litio
Sodio
Potasio

Cada elemento de la lista ya contenía el \n al final, de modo que la siguiente escritura quedaba preparada en el punto adecuado. En el caso de no fuera así deberías facilitarlo tú. Por ejemplo:

>>> b = ['Fluor', 'Cloro', 'Bromo', 'Iodo']
>>> fichero = open('prueba2.txt', 'w')
>>> for elemento in b:
  fichero.write(elemento + '\n')

  
6
6
6
5
>>> fichero.close()

El archivo final contiene cada elemento en una línea distinta, como puedes comprobar:

Fluor
Cloro
Bromo
Iodo

En lugar de

fichero.write(elemento + '\n')

podemos recurrir a la elegancia de una especificación de formato:

fichero.write('%s\n' % elemento)

Fino, ¿verdad?

Para mayor elegancia aún disponemos del método writelines(). ¿Recuerdas, en el artículo anterior, que usábamos readlines() para volcar un archivo de texto a una lista? Precisamente, writelines() hace justo lo contrario: descarga a fichero el contenido de la lista.

Volvamos a la lista de metales alcalinos, en la que cada elemento se finalizaba con \n:

>>> a
['Litio\n', 'Sodio\n', 'Potasio\n']

El método writelines() vuelca a un un archivo el contenido de una lista (o cualquier secuencia, en general). Cada elemento se escribe a continuación del anterior:

>>> fichero = open('prueba2.txt', 'w')
>>> fichero.writelines(a)
>>> fichero.close()

—-

Litio
Sodio
Potasio

La separación de líneas ha sido posible porque cada elemento de la lista contenía ya el \n final.

Esto es todo por hoy. Entendidas las técnicas básicas de lectura y escritura, estamos ya en condiciones de realizar operaciones más avanzadas.

Javier Montero Gabarró


Python: Aprendiendo a escribir


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: Aprendiendo a leer

Objetivo: aproximación al trabajo con ficheros en Python, mostrando cómo leer el contenido de un archivo de texto.

Como programador, necesitas familiarizarte cuanto antes con el trabajo con ficheros. Con frecuencia tu aplicación deberá recuperar información de un fichero para su procesamiento, o bien almacenará en él el resultado de ese proceso. Es común también el intercambio de información con el exterior en ambos sentidos: la aplicación se nutre de datos externos almacenados en ficheros y genera información que se guarda nuevamente ellos después.

Nos aproximaremos al trabajo con ficheros en Python de un modo gradual y aprenderemos a realizar las tareas más típicas partiendo de lo más simple: la lectura de un archivo de texto.

Supongo que ya conoces la diferencia entre los ficheros de texto y los binarios. Expresada de un modo simple, los primeros pueden ser leídos empleando un editor de texto plano, como gedit en Linux o el bloc de notas de Windows. Más técnicamente, podríamos decir que los ficheros de texto mantienen una codificación estándar que permite la asociación de cada byte (o un grupo de ellos) con un determinado carácter de texto, mientras que en los binarios el significado de cada byte es determinado por la propia aplicación, pudiendo representar cualquier tipo de entidad.

Ya sabes que para Python todo son objetos y, naturalmente, los ficheros también. Para que podamos interactuar con un fichero, Python crea una abstracción, un objeto, a través del cual se nos ofrece una serie de métodos para que podamos trabajar con él. Hay métodos para leer, escribir o modificar el cursor (la posición en la que se realizará la lectura o escritura), por indicar algunos.

Lo primero que debemos aprender es a crear esa abstracción, el objeto sobre el cual trabajaremos para interacturar con el fichero físico real. Es lo que se conoce como abrir el fichero.

Para hacerlo disponemos de la función open(), que usaremos del siguiente modo:

nombre_del_objeto = open(fichero_real, modo_de_apertura)

nombre_del_objeto es el nombre con el que designaremos la abstracción que envolverá al fichero_real. Dependiendo del valor que indiquemos en modo_de_apertura Python construirá un tipo de objeto u otro y determinará qué tipo de operaciones podemos realizar con él.

Iremos conociendo los distintos modos en los sucesivos artículos, pero por el momento quédate con la idea de que, cuando no se especifica un modo, Python sobreentiende que se trata de un fichero tipo texto y que sólo vas a realizar operaciones de lectura. Esto es justo lo que pretendemos lograr hoy, ser capaces de leer el contenido de un archivo de texto.

Créate un fichero de pruebas y abre un intérprete de comandos en el mismo directorio.

En este ejemplo, he creado el fichero pruebas.txt, con el siguiente contenido:

Comienza el fichero con una mención a la casa de la pradera.
La segunda línea suele hallarse después de la primera.

Esta es la cuarta línea, en la tercera había una línea en blanco.
Es una verdadera lástima que esta sea la última línea.

Observa que se trata de un fichero de cinco líneas en el que he dejado la tercera expresamente en blanco.

Para leer el fichero, la primera acción a realizar es, como hemos visto, abrirlo:

>>> fichero = open('pruebas.txt')

He elegido como nombre del objeto, fichero, sin complicarme la vida más. Entre comillas, como argumento de la función open() figura el nombre del archivo. Si no se encontrase en el mismo directorio en el que hemos ejecutado Python, deberíamos especificar su path completo.

Recuerda lo dicho anteriormente: si no indicamos un segundo parámetro con el modo de apertura, se sobreentiende el siguiente: texto y lectura.

Si tienes curiosidad por saber qué tipo de objeto ha creado Python, pregúntaselo:

>>> type(fichero)
<class '_io.TextIOWrapper'>

Que es algo así como un «envoltorio de entrada y salida texto».

Existen diversas formas de leer el fichero. Una de ellas es aprovecharnos de una particularidad muy interesante: podemos iterar sobre un fichero de texto recorriéndolo línea a línea, de modo semejante al que iteramos recorriendo una lista de principio a fin con el bucle for.

Ensayemos lo siguiente:

>>> for linea in fichero:
  print(linea)

  
Comienza el fichero con una mención a la casa de la pradera.

La segunda línea suele hallarse después de la primera.

Esta es la cuarta línea, en la tercera había una línea en blanco.

Es una verdadera lástima que esta sea la última línea.

Salvo por el detalle de que ha intercalado una línea en blanco adicional entre cada línea, el resultado es bastante decente.

Enseguida veremos cómo solucionar esto, pero antes necesito que observes un comportamiento curioso.

Vamos a intentar iterar una segunda vez y veamos qué ocurre:

>>> for linea in fichero:
  print(linea)

  
>>> 

No ha devuelto absolutamente nada. La iteración está agotada.

Python, paralelamente al proceso de lectura, actualiza un cursor indicando cúal es el siguiente elemento a leer. Como ya ha llegado al final, un nuevo intento de lectura fracasa, pues no hay nada más que leer.

¿Significa esto que no podemos leer un fichero varias veces? En absoluto. Existe un método que nos permite mover el cursor de lectura al punto deseado.

>>> fichero.seek(0)
0

Esta instrucción nos posiciona nuevamente al comienzo del fichero (carácter en la posición 0). La trataremos con detalle en otro momento, pero por ahora es suficiente con que retengas este uso.

Ya estamos en condiciones de realizar una segunda lectura, pero esta vez lo haremos sin que se impriman las líneas en blanco adicionales.

¿A qué se debe que haya dos líneas en blanco?

Python distingue una línea de otra terminándola con el carácter de nueva línea (\n). Pero, además, la función print() agrega siempre, por defecto, otro carácter de fin de línea al final, de modo que cada impresión queda separada de la anterior en una línea diferente. Por eso encontramos los dos saltos de línea: el que trae cada línea propiamente dicha más el que agrega la función print().

Para esta segunda lectura vamos a modificar la función print(), agregando un parámetro con el carácter o caracteres que deseamos que agregue al final de cada impresión, en lugar de la opción por defecto, el salto de línea. Para indicar que no queremos que agregue nada, el uso de print() debe ser el siguiente:

print(linea, end='')

De modo que nuestra iteración por líneas ahora produciría el resultado deseado:

>>> for linea in fichero:
  print(linea, end='')

  
Comienza el fichero con una mención a la casa de la pradera.
La segunda línea suele hallarse después de la primera.

Esta es la cuarta línea, en la tercera había una línea en blanco.
Es una verdadera lástima que esta sea la última línea.

Voy a presentarte a continuación un método interesante que te permite leer el fichero de una sola vez: read().

Posiciónate de nuevo al comienzo del fichero, que habrá quedado exhausto tras la lectura anterior.

>>> fichero.seek(0)
0

Y ejecuta esta nueva instrucción:

>>> fichero.read()
'Comienza el fichero con una mención a la casa de la pradera.\nLa segunda línea suele hallarse después de la primera.\n\nEsta es la cuarta línea, en la tercera había una línea en blanco.\nEs una verdadera lástima que esta sea la última línea.\n'

Devuelve un string muy largo con el contenido del fichero (probablemente tendrás que usar la barra de desplazamiento al ver esto en el navegador, pues el contenido se muestra en una única línea).

Lo importante es que se aprecia bien la estructura del fichero, con los \n separando cada línea. Fíjate también en la línea en blanco, en la posición donde está el \n\n.

Naturalmente, esta salida la obtienes a través del intérprete interactivo. Si quieres ver el resultado en un programa tendrás que usar la función print() para mostrarla.

>>> fichero.seek(0)
0
>>> print(fichero.read())
Comienza el fichero con una mención a la casa de la pradera.
La segunda línea suele hallarse después de la primera.

Esta es la cuarta línea, en la tercera había una línea en blanco.
Es una verdadera lástima que esta sea la última línea.

Una lectura con read(), al igual que la iteración, deja exhausto el fichero, posicionando el cursor de lectura al final de todo:

>>> fichero.read()
''

Presta mucha atención a esto: la cadena vacía » es el indicativo que tiene Python para detectar que ha llegado al final del archivo, hecho que podremos utilizar en nuestro código a la hora de hacer lecturas.

Otro método que debes conocer es readline() que, a diferencia del anterior, que realiza una lectura completa, recupera cada línea de una en una:

>>> fichero.seek(0)
0
>>> fichero.readline()
'Comienza el fichero con una mención a la casa de la pradera.\n'

Como el cursor estará posicionado al comienzo de la línea siguiente, cada nueva ejecución de readline() nos recuperará la línea adecuada:

>>> fichero.readline()
'La segunda línea suele hallarse después de la primera.\n'
>>> fichero.readline()
'\n'
>>> fichero.readline()
'Esta es la cuarta línea, en la tercera había una línea en blanco.\n'
>>> fichero.readline()
'Es una verdadera lástima que esta sea la última línea.\n'
>>> fichero.readline()
''

Observa nuevamente la cadena vacía para indicar que ya hemos alcanzado el final del archivo.

A continuación, uno de mis metodos favoritos: readlines(), como el anterior, pero esta vez en plural.

Este método devuelve una lista en la que cada elemento es una línea del fichero:

>>> fichero.seek(0)
0
>>> fichero.readlines()
['Comienza el fichero con una mención a la casa de la pradera.\n', 
'La segunda línea suele hallarse después de la primera.\n', 
'\n', 
'Esta es la cuarta línea, en la tercera había una línea en blanco.\n', 
'Es una verdadera lástima que esta sea la última línea.\n']

Asocia su salida a una variable y en una única lectura tendrás una lista que podrás manipular tranquilamente a tus anchas sin preocuparte de cursores.

Para finalizar, una vez hemos terminado de usar el objeto fichero, debemos proceder a cerrarlo, liberando así la memoria que estaba consumiendo y rompiendo el vínculo con el fichero real.

>>> fichero.close()

A partir de ahí, nuestra abstracción fichero dejará de estar disponible. Si necesitaras volver a hacer uso del archivo deberías abrirlo nuevamente.

Suficiente por hoy. No olvides las tres erres: read, readline y readlines.

Javier Montero Gabarró


Python: Aprendiendo a leer


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: Hace falta valor

Objetivo: entender cómo responde Python ante la modificación in situ de un objeto.

Hace unos días te presenté un fenómeno cuya comprensión era esencial para entender el modelo de memoria de Python basado en referencias. Quiero mostrarte hoy otro directamente relacionado con él.

Voy a proponerte un problema que te ayudará a testear tu conocimiento sobre Python…

Partamos de alguna operación que modifique in situ el valor de un objeto. Sin ir más lejos, tomemos, por ejemplo, el recientemente aprendido método reverse() para invertir una lista:

>>> a = [1, 2, 3]
>>> b = a.reverse()

Mi pregunta es la siguiente: ¿qué valor crees que tiene la variable b?

Recuerda que el método reverse() invierte la lista in situ (para hacerlo creando un objeto diferente recurríamos al slicing).

¿Crees que b tendrá por valor [3, 2, 1]? Se realiza la inversión y acto seguido b toma ese valor, de modo que a b le corresponde un valor de [3, 2, 1] también, como a.

O, por el contrario, ¿valdrá b, a pesar de todo [1, 2, 3]?

¿Qué piensas?

¿Sabes ya la respuesta sin comprobarla en el intérprete interactivo?

¿Por qué crees que sucede así?

¿Pondrías tu mano en el fuego?

Lamento decirte que, tanto si has elegido la primera opción como si has optado por la segunda te has equivocado completamente.

Veamos la respuesta al problema mostrando el valor de ambas variables tras la operación:

>>> a = [1, 2, 3]
>>> b = a.reverse()
>>> 
>>> a
[3, 2, 1]
>>> b
>>> 

Sorpresa: la variable b no tiene ningún valor, lo que equivale a decir que es None.

>>> type(b)
<class 'NoneType'>

Este fenómemo lo has tenido siempre delante de tus narices, aunque con mucha probabilidad te haya pasado desapercibido.

Por ejemplo, observa cómo responde el intérprete interactivo después de cualquier operación que implique la creación de un nuevo objeto:

>>> 2+3
5
>>> 'pradera'[0:3]
'pra'
>>> [1, 2, 3][::-1]
[3, 2, 1]
>>> 

Es decir, devuelve el resultado de esa operación. Si hubiésemos asignado una variable a esa operación, su valor sería precisamente ese.

Pero presta mucho atención qué sucede ante operaciones in situ, que actúan sobre el propio objeto:

>>> [1, 2, 3].append(4)
>>> [1, 2, 4].reverse()
>>> 

¡Python no devuelve absolutamente nada! O, lo que es lo mismo, devuelve el valor None.

No se trata de ningún bug de Python, sino una consideración de diseño refinadísima.

Python está diseñado expresamente así, de modo que, explícitamente, cada vez que una operación de cualquier tipo modifique in situ un objeto, no se devolverá ningún valor.

Por eso la variable b, en nuestro problema, no toma ningún valor. La inversión de la lista, desde luego, ha hecho su efecto en a, pero no hay valor devuelto por esta inversión.

Hace falta valor para tomar una decisión así, pero es algo absolutamente coherente con el modelo de memoria de Python. De no hacerlo, el sistema entero cojearía en operaciones encadenadas que combinasen modificaciones in situ con creaciones de nuevos objetos: sólo podemos encadenar operaciones (por ejemplo, ejecutando un método que actúe sobre el resultado de otro) cuando esas operaciones impliquen la creación de nuevos objetos. Si en cualquiera de ellas hay una modificación in situ no habrá valor devuelto.

En nuestro pequeño problema, la forma correcta de proceder sería esta:

>>> a = [1, 2, 3]
>>> a.reverse()
>>> b = a
>>> a
[3, 2, 1]
>>> b
[3, 2, 1]

Es decir, invertimos la lista a y sólo después realizamos la asignación de b, una vez a ha sufrido su mutación in situ.

Un pequeño precio a pagar que asegura coherencia y claridad en el código.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2012/10/python-hace-falta-valor/


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: El mundo al revés

Objetivo: aprender a invertir secuencias en Python.

¿Cansado de que tu nombre figure siempre en las últimas páginas de las listas de resultados de exámenes? ¿No has podido renovar el DNI después de varias horas esperando en una cola? Si es así, necesitas leer este artículo cuanto antes.

Voy a mostrarte cómo invertir secuencias en Python, ponerlas patas arriba y presentarlas al revés.

Comencemos considerando una cadena de caracteres cualquiera:

>>> a = 'pradera'

La técnica para invertir secuencias se basa en los slices, que ya deben resultarte familiares si has leído los artículos anteriores.

Repasemos su sintaxis:

secuencia[i:j:k]

El primer parámetro indica el índice de comienzo del trozo y el segundo el final, pero sin incluir. El tercero es opcional y, cuando está presente, indica el incremento con el que recorreremos el camino entre el principio y el fin.

Veamos algunos ejemplos:

>>> a[0:3]
'pra'

Hemos cortado un fragmento que abarca desde el carácter que tiene por índice 0 (es decir, el primero), hasta el que tiene 3 sin incluir (esto es, hasta el índice 2).

El siguiente slice hace uso de los tres parámetros:

>>> a[1:6:2]
'rdr'

Para comprenderlo, extrae primero el fragmento que correspondería a [1:6]:

'rader'

Y ahora recorre la secuencia de dos en dos, empezando por el primero:

'rdr'

El siguiente ejemplo muestra la omisión del primer parámetro, indicando que comenzamos desde el principio:

>>> a[:4]
'prad'

O del segundo, lo que significa que sigue hasta el final:

>>> a[3:]
'dera'

O de ambos:

>>> a[:]
'pradera'

Recuerda que ya presentamos esta última técnica como método para duplicar una secuencia.

Visto este pequeño repaso, lo que nos interesa muy particularmente es el caso en el que el tercer parámetro del slice es negativo. Eso significa que el fragmento se extrae no de izquierda a derecha, sino al revés, de derecha a izquierda.

Observa el ejemplo:

>>> a[5:1:-1]
'reda'

Analicemos esto con cuidado esto para asegurarnos de que lo entendemos bien:

Lo primero que quizás te llame la atención es que el primer parámetro es mayor que el segundo. Esto es así debido a que estamos recorriendo la secuencia de derecha a izquierda. El índice de comienzo siempre será más alto (o al menos igual) que el índice de destino.

Comenzamos el corte hacia atrás desde el carácter que tiene por índice 5: ‘r’.

¿Y dónde terminamos? En el inmediatamente anterior al indicado en el segundo parámetro. Puesto que estamos recorriendo la secuencia al revés, el anterior del índice 1 no es el índice cero sino 2: ‘a’.

Y ahora sí, tomamos de derecha a izquierda todos esos caracteres, desde un extremo hasta el otro:

'reda'

Ya estás en condiciones de entender lo que hace esto:

>>> a[::-1]
'aredarp'

Es nuestro buscado string invertido.

Como no fijamos valores iniciales ni finales estamos indicando que actuaremos sobre la cadena completa.

Apréndete bien esta técnica, es el procedimiento básico para invertir secuencias, algo que tendrás que realizar con frecuencia en tu vida como programador.

Naturalmente, con las listas (un tipo de secuencias) otro tanto de lo mismo:

>>> a = [1, 2, 3]
>>> a[::-1]
[3, 2, 1]

Es muy importante que tengas siempre presente que el slicing siempre genera un objeto nuevo. Con los strings puede parecer obvio, ya que son inmutables, pero quizás no tanto con las listas, que no lo son (pueden modificarse in-situ).

Constata que la lista sigue siendo la misma:

>>> a
[1, 2, 3]

Por último, voy a enseñarte otra técnica muy útil para invertir listas, pero con la particularidad de que realizaremos una operación destructiva, modificando in-situ la lista (aprovechándonos de su mutabilidad): el método reverse().

>>> a.reverse()
>>> a
[3, 2, 1]

Observa que no ha habido creación de un duplicado, sino que el objeto original ha sido directamente modificado.

La siguiente lista muestra el resultado de una carrera entre varios colegas:

>>> clasificacion = ['Jesús', 'Pedro', 'José Luis', 'Javier']

No es que me importe particularmente quedarme el último pero, si dispongo de recursos, ¿por qué no los habría de utilizar?

>>> clasificacion.reverse()
>>> clasificacion
['Javier', 'José Luis', 'Pedro', 'Jesús']

Ni slicing ni gaitas: he preferido actuar directamente sobre el objeto, destruyendo el anterior.

Y ahora eso ya tiene otra pinta, ¿somos pythonistas o no?

Javier Montero Gabarró


Python: El mundo al revés


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: Te repites más que el ajo

Objetivo: aprender a contar las veces que un determinado elemento se repite dentro de una secuencia en Python.

Tarde o temprano tendrás la necesidad de saber cuántas veces ocurre una letra o palabra en determinada frase, o las veces que un elemento aparece en una lista o tupla.

Estos tres tipos, strings, listas y tuplas, pertenecen a la categoría de secuencias en Python, y como buenos amigos, comparten una serie de métodos comunes.

Uno de ellos es count(), que nos sirve para saber cuántas veces sucede un elemento dentro de una secuencia.

Imagínate la siguiente lista:

>>> lista = [3, 7, 6, 2, 1, 7, 3, 1, 1, 5]

¿Cuántas veces aparece el número 1? ¿Y el 4?

>>> lista.count(1)
3
>>> lista.count(4)
0

Con las tuplas es exactamente lo mismo.

Consideremos ahora una cadena de caracteres:

>>> frase = 'la casa de la pradera'

¿Cuántas aes hay? ¿Cuántas veces está la cadena ‘la’?

>>> frase.count('a')
6
>>> frase.count('la')
2

Voy a proponerte un problema para que lo madures. Toma la cadena s = 'lalalala'

¿Qué crees que devolverá s.count('ala')? ¿Por qué?

El método count(), aplicado a un string, tiene algunas sutilezas más respecto a su versión para listas o tuplas. Hablaremos de ellas en otro momento.

Anoche, mientras trabajaba en un programa, me encontré con una lista de 325 strings en la que sabía a ciencia cierta que deberían haber sido 324. Uno de ellos estaba duplicado y era preciso saber cuál.

Hay muchas maneras de resolver este problema sencillo, sin necesidad de ponerme a buscar a pelo de uno en uno. Una de ellas emplea el método count().

for elemento in lista:
    if lista.count(elemento) > 1:
        print(elemento)

Recorremos de principio a fin la lista con un bucle for y en cada parada hacemos una comprobación: si el número de veces que aparece ese elemento es mayor que uno, lo mostramos.

Tras lo cual apareció el polizón (que, naturalmente, se mostró dos veces) y pude deshacerme de él.

Javier Montero Gabarró


Python: Te repites más que el ajo


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: Cómo copiar un diccionario

Objetivo: aprender a copiar un diccionario en Python, evitando referencias al mismo objeto.

Al igual que las listas, los diccionarios, como sabes, tienen cosquillas (no son inmutables). Padecen el mismo problema que aquéllas a la hora de copiarlas: podemos obtener referencias al mismo objeto que, si no somos cuidadosos, pueden llevarnos a un buen quebradero de cabeza.

Observa el fenómeno:

>>> x = {'manzana':'verde', 'plátano':'amarillo'}
>>> y = x
>>> y
{'plátano': 'amarillo', 'manzana': 'verde'}

Aparentemente, aunque x e y tengan el mismo valor, se trataría de objetos distintos y cada uno podría vivir, desde este momento, su propia vida independiente. Al menos, eso es lo que esperaríamos en otros lenguajes de programación.

Pero no es así, uno de los grandes atractivos de Python: x e y no son más que dos collares en el mismo perro.

>>> y is x
True

De hecho, si modificamos x, los cambios también se reflejan en y:

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

Entonces, ¿cuál es el modo correcto de obtener un duplicado independiente de un diccionario?

Los diccionarios tienen una inmesa colección de metodos que, poco a poco, conviene ir aprendiendo. Uno de ellos, copy(), soluciona nuestro problema:

>>> z = x.copy()
>>> z
{'fresa': 'roja', 'plátano': 'amarillo', 'manzana': 'verde'}

La variable z apunta a un duplicado de x, pero observa que ahora son objetos distintos:

>>> z is x
False

Si modificamos x podemos comprobar que z no se ve afectada:

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

Habríamos llegado al mismo resultado a través de la función dict(), empleada para construir diccionarios:

>>> z = dict(x)

Hablaremos de dict() con mucho más detalle más adelante. Quédate, hasta entonces, con estos dos modos de duplicar diccionarios.

Observa que la variable y, copia burda de x, se ha quedado sin su tan rico en potasio plátano.

>>> y
{'fresa': 'roja', 'manzana': 'verde'}

Se lo merece, ¡esto es Python!

Javier Montero Gabarró


Python: Cómo copiar 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: Cómo copiar una lista

Objetivo: aplicar las técnicas de slicing de secuencias para obtener un duplicado de una lista.

En el artículo anterior, El sagrado misterio de la inmutabilidad, pudimos apreciar un fenómeno curioso a la hora de trabajar con listas.

Supongamos las siguientes asignaciones aparentemente inocentes:

>>> x = [1, 2]
>>> y = x

Tiene toda la pinta de que y es una copia de x, ¿no?.

>>> y
[1, 2]

Si ahora modificamos la lista x:

>>> x.append(3)
>>> x
[1, 2, 3]

¿Qué habrá sucedido con y?

>>> y
[1, 2, 3]

Atención: ¡los cambios en x también han ocurrido en y! Esto es Python.

Lo que está pasando es que x e y se corresponden con el mismo objeto en memoria. Esto no tendría la menor importancia desde el punto de vista del programador si el objeto en cuestión fuera inmutable, como un número, un string o una tupla, pues no pueden ser modificados in situ. En cambio, con las listas tenemos un serio problema, como hemos podido comprobar.

¿Cómo hacemos, entonces, si necesitamos duplicar una lista de modo que cada una pueda vivir su vida libre independientemente de la otra?

Las técnicas de slicing de secuencias, que ya hemos dejado caer con anterioridad, permiten la independencia de las listas clonadas.

Repasemos brevemente el concepto de slicing, o troceado de una secuencia.

>>> x = 'pradera'
>>> x[1:5]
'rade'

Con esa instrucción extraemos desde el elemento cón índice 1 (recuerda que, en las secuencias, el primer elemento tiene por índice cero) hasta, y sin incluir, el de índice 5; es decir, desde el 1 al 4.

Fíjate en el formato de la instrucción: entre corchetes y separando los límites mediante los dos puntos.

Podemos omitir uno de los índices:

>>> x[:5]
'prade'

que equivale a tomar todos los caracteres desde el principio hasta el de índice cuatro.

>>> x[3:]
'dera'

que es lo mismo que extraer desde el que tiene por índice 3 hasta el último de la secuencia.

O también podemos suprimir los dos, equivalente a extraer todo desde el principio hasta el fin:

>>> x[:]
'pradera'

¿Qué sentido tiene realizar algo así, te preguntarás?

La clave estriba en que siempre que hagamos un slicing de una lista, obtendremos un objeto distinto, aunque sea un slicing como el anterior, de principio a fin.

Obsérvalo:

>>> x = [1, 2]
>>> y = x[:]
>>> y
[1, 2]

Tras esta operación y contiene el resultado de la extracción completa de los elementos de x, pero ahora sí que se trata de un duplicado independiente. Comprobémoslo:

>>> id(x)
162280364
>>> id(y)
162280556

También podríamos haber empleado el operador is para verificar si dos variables apuntan al mismo objeto, lo que es más rápido que comprobar las identidades individuales:

>>> x is y
False

Hemos logrado separar a las listas siamesas. Una última comprobación:

>>> x.append(3)
>>> x
[1, 2, 3]
>>> y
[1, 2]

Ley de vida: x e y dejan de ser almas paralelas y cada una recorre ahora su propio camino hasta que, inevitablemente, llegue el día en que dejen de existir.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2012/09/python-como-copiar-una-lista/


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: El sagrado misterio de la inmutabilidad

Objetivo: comprender los conceptos críticos de mutabilidad, inmutabilidad y referencia en Python.

Estás ante un artículo esencial en tu formación como programador en Python. Te llevará sólo cinco minutos leerlo, pero puede dar luz sobre conceptos que no resultan ni mucho menos obvios cuando se comienza con Python, particularmente si procedes de otros lenguajes de programación.

Por lo general, cuando empezamos a estudiar un lenguaje de programación, se nos cuenta que existen distintos tipos de datos, tales como numéricos, strings, etc.

En Python se nos enseña algo más: determinados tipos son inmutables y otros mutables. Los números, los strings y las tuplas son inmutables. Por el contrario, las listas son mutables.

Ahí ya empiezan a sacudirnos algo; pero nuestro cerebro, al que no le gustan las dudas, intenta buscar una respuesta coherente para no quedarse atascado y seguir avanzando. Claro: los números, los strings y las tuplas no se pueden modificar, mientras que las listas .

Bueno, bueno, un momento:

>>> a = 5
>>> b = 'pradera'

La variable a contiene un número; la variable b contiene un string. Hemos dicho que los números y los strings son inmutables. ¿Significa eso que no podemos modificar ni a ni b?

>>> a = 6
>>> b = 'casa'
>>> a
6
>>> b
'casa'

Pues sí, se pueden modificar (de no ser así Python tendría un serio problema), por lo que eso de la inmutabilidad debe de significar algo diferente. Decir que un tupla es inmutable, pero una lista no, ¿significará acaso que ésta tiene cosquillas pero la otra no?

Más adelante cuando estudiamos las listas y las tuplas creemos haber comprendido, al fin, el misterio.

>>> lista = [1, 2, 3, 4]
>>> lista[0] = 5
>>> lista
[5, 2, 3, 4]

Bien: las listas, mutables, se pueden modificar.

>>> tupla = (1, 2, 3, 4)
>>> tupla[0] = 5
Traceback (most recent call last):
  File "<pyshell#55>", line 1, in <module>
    tupla[0] = 5
TypeError: 'tuple' object does not support item assignment

En cambio, las tuplas, inmutables, no, como podemos comprobar.

Aprendemos también que los strings también son secuencias, como las listas y las tuplas y, como tales, podemos acceder a sus caracteres individuales:

>>> serie = 'la casa de la pradera'
>>> serie[3]
'c'

Pero no podemos modificarlos:

>>> serie[3] = 'k'
Traceback (most recent call last):
  File "<pyshell#60>", line 1, in <module>
    serie[3] = 'k'
TypeError: 'str' object does not support item assignment

Un error semejante al que recibimos al tratar de modificar una tupla. Esto hace que cuadre todo: los strings son inmutables, también.

Pero ¿cuadra realmente todo? Parece que sí, aunque no aparenta tener mucho sentido práctico eso de la inmutabilidad de los números.

Tarde o temprano, cualquier estudiante de Python que ya ha programado en otros lenguajes se enfrenta al siguiente misterio.

Observémoslo muy despacio:

>>> x = 5
>>> y = x

Pregunta: ¿cuánto crees que vale y?

En efecto, 5:

>>> y
5

Modifiquemos ahora el valor de x:

>>> x = 6

¿Cuánto crees que valdrá ahora y?

Vamos a ver, no me asustes: x e y son dos variables diferentes, cada una con su propio contenido; por lo tanto y tiene que seguir valiendo 5, aunque hayas modificado x, ¿no?

En efecto, así es:

>>> y
5

Veamos otro ejemplo. Ahora x es una lista:

>>> x = [1, 2, 3, 4]
>>> y = x
>>> y
[1, 2, 3, 4]

Voy a modificar el valor de x:

>>> x[0] = 5
>>> x
[5, 2, 3, 4]

¿Cuánto crees que valdrá ahora y?

Por la lógica anterior, x e y son dos variables diferentes, cada una con su propio contenido, por lo que cabría esperar que el valor de y fuera [1, 2, 3, 4].

Pero no es así:

>>> y
[5, 2, 3, 4]

Esto rompe completamente nuestros esquemas. Si somos programadores en otros lenguajes una alarma nos sacude inmediatamente.

¿Por qué al modificar x ha cambiado y también?

De acuerdo: los números son inmutables, pero las listas no. ¿Pero qué tiene que ver esto con el hecho de que se haya modificado el valor de y?

Para resolver el misterio hace falta un una nueva pieza clave: el concepto de referencia.

Veamos lo que está sucediendo realmente entre bastidores:

>>> x = 5

En Python, todo son objetos. Se acaba de crear uno nuevo: un número de valor 5.

Este objeto, que reside en algún lugar de la memoria, posee un identificador único que lo diferencia del resto de los objetos. Piensa en él como si fuera su DNI (es, en realidad, la dirección de memoria en la que reside el objeto).

Para conocer ese identificador, Python dispone de la función id():

>>> id(5)
137396064

Y ahora el concepto crítico: la variable x no es más que una referencia a ese objeto. A efectos prácticos, es como si se tratara de un puntero (empleando conceptos de otros lenguajes) a ese objeto. No contiene su valor, sino una referencia a él.

La función id(), aplicada a una variable, nos devuelve el id del objeto al que referencia, por lo que obtenemos el mismo valor que antes:

>>> id(x)
137396064

Proseguimos; asignamos a la variable y el valor de x:

>>> y = x

Observa ahora cuidadosamente qué pasa al preguntar por el id del objeto al que referencia y:

>>> id(y)
137396064

Exactamente el mismo al que referencia x. Tanto x como y apuntan al mismo objeto.

Este es un concepto radicalmente distinto al de las variables en otros lenguajes, en los que el contenido de x y de y estaría en diferentes direcciones de memoria.

A continuación, modificamos x:

>>> x = 6
>>> id(x)
137396080

Se ha creado un nuevo objeto, de valor 6, y ahora x apunta a ese valor. Esto también es muy diferente a lo que sucedería en otros lenguajes: la variable x seguiría en la misma dirección de memoria, habiendo modificado únicamente su contenido.

Fijémonos que, como es de esperar, y sigue apuntando al objeto primero:

>>> id(y)
137396064
>>> y
5

Analicemos ahora qué sucede en el caso de las listas:

>>> x = [1, 2, 3, 4]
>>> y = x
>>> id(x)
170964396
>>> id(y)
170964396

De momento, todo es exactamente igual que antes: se ha creado un único objeto, la lista [1, 2, 3, 4], que está referenciado por dos variables, x e y.

Si ahora modificamos directamente el objeto (al ser mutable, podemos hacerlo):

>>> x[0] = 5
>>> id(x)
170964396
>>> id(y)
170964396

comprobamos que tanto x como y siguen siendo referencias al mismo objeto.

Por lo tanto y tiene el mismo valor que x:

>>> y
[5, 2, 3, 4]

En el ejemplo anterior, cuando hicimos x = 6, se creó un nuevo objeto. En el caso de la lista, hemos modificado in situ el propio objeto, aprovechándonos de su mutabilidad. Es como si un cirujano hubiese realizado una operación sobre el objeto.

La situación habría sido muy distinta si hubiéramos hecho esto otro:

>>> x = [1, 2, 3, 4]
>>> y = x
>>> x = [5, 2, 3, 4]
>>> y
[1, 2, 3, 4]
>>> id(x)
170489580
>>> id(y)
170791756

Fíjate en la importante diferencia: al hacer x = [5, 2, 3, 4] hemos creado un objeto diferente, de modo que x e y apuntan a objetos distintos y por eso ahora sus valores difieren. En el caso anterior, al hacer x[0] = 5 modificamos directamente el mismo objeto y no se creó otro nuevo.

Espero que todo resulte más claro ahora y entiendas la diferencia esencial que hay en lo que respecta al concepto de variable respecto a otros lenguajes de programación. Si es así, felicítate, pues habrás cambiado de nivel en tu proceso de aprendizaje de Python.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2012/09/python-el-sagrado-misterio-de-la-inmutabilidad/


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.

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.