Este capítulo describe con más detalle algunas cosas que ya has visto y añade algunas cosas nuevas.
El tipo de datos ``lista'' tiene algunos métodos más. Éstos son todos los métodos de los objetos lista:
append(x)
a[len(a):] = [x]
.
extend(L)
a[len(a):] = L
.
insert(i, x)
a.insert(0, x)
inserta al principio de la lista y a.insert(len(a), x)
equivale a
a.append(x)
.
remove(x)
x
.
Provoca un error si no existe tal elemento.
index(x)
x
.
Provoca un error si no existe tal elemento.
count(x)
x
en la lista.
sort()
reverse()
Un ejemplo que utiliza varios 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]
Los métodos de las listas facilitan mucho usar una lista como una pila, en donde el último elemento añadido es el primer elemento recuperado. (``last-in, first-out'', ``último en llegar, primero en salir''). Para apilar un elemento, usa append(). Para recuperar el elemento superior de la pila, usa pop() sin un índice explícito. Por ejemplo:
>>> pila = [3, 4, 5] >>> pila.append(6) >>> pila.append(7) >>> pila [3, 4, 5, 6, 7] >>> pila.pop() 7 >>> pila [3, 4, 5, 6] >>> pila.pop() 6 >>> pila.pop() 5 >>> pila [3, 4]
También es muy práctico usar una lista como cola, donde el primer
elemento que se añade a la cola es el primero en salir
(``first-in, first-out'', ``primero en llegar, último en salir'').
Para añadir un elemento al final de una cola, usa
append(). Para recuperar el primer elemento de la cola,
usa pop() con 0
de índice. Por ejemplo:
>>> cola = ["Eric", "John", "Michael"] >>> cola.append("Terry") # llega Terry >>> cola.append("Graham") # llega Graham >>> cola.pop(0) 'Eric' >>> cola.pop(0) 'John' >>> cola ['Michael', 'Terry', 'Graham']
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
Las LCs proporcionan un modo conciso de crear listas sin recurrir al uso de map(), filter() ni lambda. La definición de lista resultante tiende a ser más clara que las listas construidas con los métodos citados. Cada LC consta de de una expresión seguida de una cláusula for y cero o más cláusulas for o if. La lista resultante se obtiene evaluando la expresión en el contexto de las cláusulas for e if que la siguen. Si la expresión debe dar como resultado una tupla, hay que encerrarla entre paréntesis.
>>> frutafresca = [' plátano', ' mora ', 'fruta de la pasión '] >>> [arma.strip() for arma in frutafresca] ['plátano', 'mora', 'fruta de la pasión'] >>> vec = [2, 4, 6] >>> [3*x for x in vec] [6, 12, 18] >>> [3*x for x in vec if x > 3] [12, 18] >>> [3*x for x in vec if x < 2] [] >>> [{x: x**2} for x in vec] [{2: 4}, {4: 16}, {6: 36}] >>> [[x,x**2] for x in vec] [[2, 4], [4, 16], [6, 36]] >>> [x, x**2 for x in vec] # error - se necesita un paréntesis en las tuplas File "<stdin>", line 1 [x, x**2 for x in vec] ^ SyntaxError: invalid syntax >>> [(x, x**2) for x in vec] [(2, 4), (4, 16), (6, 36)] >>> vec1 = [2, 4, 6] >>> vec2 = [4, 3, -9] >>> [x*y for x in vec1 for y in vec2] [8, 6, -18, 16, 12, -36, 24, 18, -54] >>> [x+y for x in vec1 for y in vec2] [6, 5, -7, 8, 7, -5, 10, 9, -3]
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.
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). También es posible crear tuplas que contengan objetos mutables, por ejemplo, listas.
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 secuencias. El desempaquetado de secuencias requiere que el número de variables sea igual al número de elementos de la secuencia. Observa que la asignación múltiple sólo es un efecto combinado del empaquetado de tuplas y desempaquetado de secuencias.
Esto resulta un poco asimétrico, ya que el empaquetado de varios valores siempre resulta en una tupla, aunque el desempaquetado funciona para cualquier secuencia.
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. Si una tupla contiene cualquier objeto mutable directa o indirectamente, no se puede usar como clave. No se pueden utilizar las listas como claves, ya que las listas se pueden modificar, por ejemplo, mediante el método append() y su método extend(), además de las asignaciones de corte y asignaciones aumentadas.
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 clave:
valor entre las llaves se
añaden parejas clave:
valor 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 clave:
valor
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
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. Los programadores en C pueden quejarse de esto,
pero evita una causa común problemas hallados en los programas en C: teclear
=
en una expresión en la que se quería decir ==
.
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