Subsecciones


5. Estructuras de datos

Este capítulo describe con más detalle algunas cosas que ya has visto y añade algunas cosas nuevas.


5.1 Más sobre las listas

El tipo de datos ``lista'' tiene algunos métodos más. Éstos son todos los métodos de los objetos lista:

insert(i, x)
Inserta un elemento en un posición dada. El primer argumento es el índice del elemento antes del que se inserta, por lo que a.insert(0, x) inserta al principio de la lista y a.insert(len(a), x) equivale a a.append(x).

append(x)
Añade un elemento al final de la lista; a.append(x) equivale a a.insert(len(a), x).

index(x)
Devuelve el índice del primer elemento de la lista cuyo valor sea x. Provoca un error si no existe tal elemento.

remove(x)
Elimina el primer elemento de la lista cuyo valor es x. Provoca un error si no existe tal elemento.

sort()
Ordena ascendentemente los elementos de la propia lista (la lista queda cambiada).

reverse()
Invierte la propia lista (la lista queda cambiada).

count(x)
Devuelve el número de veces que aparece x en la lista.

Un ejemplo que utiliza todos los métodos de la lista:

>>> a = [66.6, 333, 333, 1, 1234.5]
>>> print a.count(333), a.count(66.6), a.count('x')
2 1 0
>>> a.insert(2, -1)
>>> a.append(333)
>>> a
[66.6, 333, -1, 333, 1, 1234.5, 333]
>>> a.index(333)
1
>>> a.remove(333)
>>> a
[66.6, -1, 333, 1, 1234.5, 333]
>>> a.reverse()
>>> a
[333, 1234.5, 1, 333, -1, 66.6]
>>> a.sort()
>>> a
[-1, 1, 66.6, 333, 333, 1234.5]


5.1.1 Herramientas de programación funcional

Hay tres funciones internas que son muy útiles al tratar con listas: filter(), map() y reduce().

"filter(función, secuencia)" (filtrar) devuelve una secuencia (del mismo tipo, si es posible) que contiene aquellos elementos de la secuencia para los que función(elemento) resulta verdadero. Por ejemplo, para calcular algunos primos:

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]

"map(función, secuencia)" (transformar) llama a función(elemento) para cada uno de los elementos de la secuencia y devuelve una lista compuesta por los valores resultantes. Por ejemplo, para calcular algunos cubos:

>>> def cubo(x): return x*x*x
...
>>> map(cubo, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

Se puede pasar más de una secuencia como parámetro. La función debe tener tantos argumentos como secuencias se le pasan y se llama a la función con el valor correspondiente de cada secuencia de entrada (o None si una secuencia es más corta que otra). Si se pasa None como función, se utiliza la función identidad, que devuelve sus argumentos.

Combinando estos dos casos especiales vemos que "map(None, lista1, lista2)" es un modo muy cómodo de convertir una pareja de listas en una lista de parejas. Por ejemplo:

>>> secuencia = range(8)
>>> def cuadrado(x): return x*x
...
>>> map(None, secuencia, map(cuadrado, secuencia))
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)]

"reduce(func, secuencia)" (reducir) devuelve un valor simple que se construye llamando a la función binaria func con los dos primeros elementos de la secuencia, luego con el resultado y el siguiente elemento y así sucesivamente. Por ejemplo, para calcular la suma de los números de 1 a 10:

>>> def suma(x,y): return x+y
...
>>> reduce(suma, range(1, 11))
55

Si sólo hay un elemento en la secuencia, se devuelve su valor; si la secuencia está vacía, se lanza una excepción.

Se puede pasar un tercer argumento para indicar el valor inicial. En este caso, se devuelve este valor inicial para la secuencia vacía y la función se aplica al primer elemento, luego al segundo y así sucesivamente. Por ejemplo,

>>> def sum(secuencia):
...     def suma(x,y): return x+y
...     return reduce(suma, secuencia, 0)
... 
>>> sum(range(1, 11))
55
>>> sum([])
0


5.2 La sentencia del

Hay un modo de eliminar un elemento de una lista dado su índice en lugar de su valor: la sentencia del. También se puede utilizar para eliminar cortes de una lista (lo que hacíamos antes asignando una lista vacía al corte). Por ejemplo:

>>> a
[-1, 1, 66.6, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.6, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.6, 1234.5]

del se puede utilizar para eliminar variable completas:

>>> del a

Hacer referencia al nombre a a partir de aquí provoca un error (al menos hasta que se asigne otro valor al nombre). Veremos otros usos de del más adelante.


5.3 Tuplas y secuencias

Hemos visto que las listas y las cadenas tienen muchas propiedades en común, por ejemplo, el indexado y el corte. Son dos ejemplos de tipos de datos secuenciales. Como Python es un lenguaje en evolución, se pueden añadir otros tipos de datos de secuencia. Hay otro tipo de datos secuencial: la tupla.

Una tupla consta de cierta cantidad de valores separada por comas, por ejemplo:

>>> t = 12345, 54321, '¡hola!'
>>> t[0]
12345
>>> t
(12345, 54321, '¡hola!')
>>> # Se pueden anidar tuplas:
... u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, '¡hola!'), (1, 2, 3, 4, 5))

Como puedes observar, en la salida se encierran las tuplas entre paréntesis, para que las tuplas anidadas se interpreten correctamente. En la entrada los paréntesis son opcionales, aunque a menudo son necesarios (si la tupla es parte de una expresión más compleja).

Las tuplas son muy útiles: Pares de coordenadas (x,y), registros de empleados de una base de datos, etc. Las tuplas, como las cadenas, son inmutables: No es posible asignar un valor a los elementos individuales de una tupla (se puede simular el mismo efecto mediante corte y concatenación, sin embargo).

Un problema especial es la construcción de tuplas de 0 ó 1 elementos: La sintaxis tiene trucos para resolver esto. Las tuplas vacías se construyen mediante un par de paréntesis vacío y las tuplas de un solo elemento se construyen mediante el valor del elemento seguido de coma (no vale con encerrar el valor entre paréntesis). Es feo, pero funciona. Por ejemplo:

>>> vacio = ()
>>> singleton = 'hola',    # <-- Observa la coma final
>>> len(vacio)
0
>>> len(singleton)
1
>>> singleton
('hola',)

La sentencia t = 12345, 54321, '¡hola!' es un ejemplo de empaquetado de tuplas: los valores 12345, 54321 y '¡hola!' se empaquetan en una tupla. También se puede realizar la operación inversa:

>>> x, y, z = t

Esto se llama, por supuesto, desempaquetado de tuplas. El desempaquetado de tuplas requiere que el número de variables sea igual al número de elementos de la tupla. Observa que la asignación múltiple sólo es un efecto combinado del empaquetado y desempaquetado de tuplas.

En algún momento puede resultar útil la operación correspondiente sobre listas: desempaquetado de listas. Esto se lleva a cabo encerrando la lista de variables entre corchetes:

>>> a = ['fiambre', 'huevos', 100, 1234]
>>> [a1, a2, a3, a4] = a


5.4 Diccionarios

Otro tipo de dato interno de Python que resulta útil es el diccionario. Los diccionarios aparecen a veces en otros lenguajes como ``memorias asociativas'' o ``matrices asociativas''. A diferencia de las secuencias, que se indexan mediante un rango de números, los diccionarios se indexan mediante claves, que pueden ser de cualquier tipo inmutable. Siempre se puede utilizar cadenas y números como claves. Las tuplas pueden usarse de claves si sólo contienen cadenas, números o tuplas. No se pueden utilizar las listas como claves, ya que las listas se pueden modificar, por ejemplo, mediante el método append().

Lo mejor es pensar en un diccionario como en un conjunto desordenado de parejas clave, valor, con el requisito de que las claves sean únicas (dentro del mismo diccionario). Una pareja de llaves crea un diccionario vacío: {}. Si se coloca una lista de parejas clavevalor entre las llaves se añaden parejas clavevalor iniciales al diccionario. Así es como se presentan los diccionarios en la salida (hay ejemplos dentro de poco).

Las operaciones principales sobre un diccionario son la de almacenar una valor con una clave dada y la de extraer el valor partiendo de la clave. También se puede eliminar una pareja clavevalor con del. Si se introduce una clave que ya existe, el valor anterior se olvida. Intentar extraer un valor utilizando una clave no existente provoca un error.

El método keys() de un objeto de tipo diccionario devuelve todas las claves utilizadas en el diccionario, en orden aleatorio (si deseas ordenarlas, aplica el método sort() a la lista de claves). Para comprobar si una clave existe en el diccionario, utiliza el método has_key()del diccionario.

He aquí un pequeño ejemplo que utiliza un diccionario:

>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> tel['jack']
4098
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'guido': 4127, 'irv': 4127, 'jack': 4098}
>>> tel.keys()
['guido', 'irv', 'jack']
>>> tel.has_key('guido')
1


5.5 Más sobre las condiciones

Las condiciones utilizadas en construcciones while e if descritas anteriormente pueden contener otros operadores, además de las comparaciones.

Los operadores de comparación in (dentro de) y not in (no está dentro de) comprueban si un valor está incluido (o no) en una secuencia. Los operadores is (es) y is not (no es) comparan si dos objetos son en realidad el mismo. Esto sólo tiene importancia en los objetos mutables, como las listas. Todos los operadores de comparación tienen la misma prioridad, que es menor que la de los operadores numéricos.

Se pueden encadenar las comparaciones: Por ejemplo, a < b == c comprueba si a es menor que b y además si b es igual a c.

Las comparaciones se pueden combinar mediante los operadores lógicos and (y) y or (o) y la salida de una comparación (o cualquier otra expresión lógica) se puede negar mediante not (no). Todos éstos tienen menor prioridad que los operadores de comparación. Entre ellos, not tiene la prioridad más elevada y or la más baja, por lo que A and not B or C equivale a (A and (not B)) or C. Por supuesto, se pueden utilizar paréntesis para expresar un orden de operación concreto.

Los operadores lógicos and y or se denominan operadores de atajo: Sus argumentos se evalúan de izquierda a derecha y la evaluación se interrumpe tan pronto como queda determinado el valor de salida. Por ejemplo, si A tiene un valor de verdadero pero B es falso, A and B and C no evalúa el valor de la expresión C. En general, el valor devuelto por un operador de atajo, cuando se utiliza como valor en general y no como valor lógico, es el último argumento evaluado.

Es posible asignar el resultado de una comparación u otra expresión lógica a una variable. Por ejemplo:

>>> cadena1, cadena2, cadena3 = '', 'Trondheim', 'Hammer Dance'
>>> non_null = cadena1 or cadena2 or cadena3
>>> non_null
'Trondheim'

Observa que en Python, al contrario que en C, no puede haber asignación dentro de una expresión.


5.6 Comparación entre secuencias y otros tipos

Los objetos de secuencia se pueden comparar con otros objetos del mismo tipo de secuencia. La comparación utiliza ordenación lexicográfica: Primero se comparan los dos primeros elementos, si estos difieren ya está determinado el valor de la comparación, si no, se comparan los dos elementos siguientes de cada secuencia y, así sucesivamente, hasta que se agota alguna de las dos secuencias. Si alguno de los elementos que se compara es él mismo una secuencia, se lleva a cabo una comparación lexicográfica anidada. Si todos los elementos son iguales, se considera que las secuencias son iguales. Si una de las secuencias es igual a la otra truncada a partir de cierto elemento, la secuencia más corta de las dos es la menor. La ordenación lexicográfica para las cadenas utiliza el orden de los códigos ASCII de sus caracteres. He aquí ejemplos de comparaciones entre secuencias del mismo tipo:

(1, 2, 3)              < (1, 2, 4)
[1, 2, 3]              < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4)           < (1, 2, 4)
(1, 2)                 < (1, 2, -1)
(1, 2, 3)             == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)

Observa que es legal comparar objetos de tipos diferentes. El resultado es determinístico pero arbitrario: los tipos se ordenan por su nombre. De este modo, una lista siempre es menor que una cadena, una cadena siempre es menor que una tupla, etc. Los valores numéricos de tipos diferentes se comparan por su valor numérico, por lo que 0 es igual a 0.0, etc.5.1



Notas al pie

... etc.5.1
Las reglas de comparación entre objetos de tipos diferentes no son fiables. Pueden cambiar en versiones futuras del lenguaje.


Envía los comentarios sobre este documento a python-docs@python.org (en inglés). Envía los comentarios sobre la traducción a Marcos.