3.6. Inyección de listas (mapping)

Una de las características más potentes de Python es la lista por comprensión (list comprehension), que proporciona una forma compacta de inyectar una lista en otra aplicando una función a cada uno de sus elementos.

Ejemplo 3.24. Presentación de las listas por comprensión (list comprehensions)

>>> li = [1, 9, 8, 4]
>>> [elem*2 for elem in li]      1
[2, 18, 16, 8]
>>> li                           2
[1, 9, 8, 4]
>>> li = [elem*2 for elem in li] 3
>>> li
[2, 18, 16, 8]
1 Para que esto tenga sentido, léalo de derecha a izquierda. li es la lista que está inyectando. Python itera sobre li elemento a elemento, asignando temporalmente el valor de cada elemento a la variable elem. Python aplica entonces la función elem*2 y añade el resultado a la lista que ha de devolver.
2 Observe que las listas por comprensión no modifican la original.
3 Es seguro asignar el resultado de una lista por comprensión a la variable que está inyectando. Python construye la nueva lista en memoria, y cuando la completa asigna el resultado a la variable.

Aquí está la lista por comprensión de la función buildConnectionString que declaramos en Capítulo 2:

["%s=%s" % (k, v) for k, v in params.items()]

Primero, comprobará que está llamando a la función items del diccionario params. Esta función devuelve una lista de tuplas con todos los datos del diccionario.

Ejemplo 3.25. Las funciones keys, values, e items

>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> params.keys()   1
['server', 'uid', 'database', 'pwd']
>>> params.values() 2
['mpilgrim', 'sa', 'master', 'secret']
>>> params.items()  3
[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
1 El método keys de un diccionario devuelve una lista de todas las claves. La lista no está en el orden en que se definió el diccionario (recuerde que los elementos de un diccionario no tienen orden), pero es una lista.
2 El método values devuelve una lista de todos los valores. La lista está en el mismo orden que la devuelta por keys, de manera que params.values()[n] == params[params.keys()[n]] para todos los valores de n.
3 El método items devuelve una lista de tuplas de la forma (clave, valor). La lista contiene todos los datos del diccionario.

Ahora veamos qué hace buildConnectionString. Toma una lista, params.items(), y la inyecta en una nueva lista aplicando formato de cadenas a cada elemento. La nueva lista contendrá el mismo número de elementos que params.items(), pero cada uno de estos nuevos elementos será una cadena que contenga una clave y su valor asociado en el diccionario params.

Ejemplo 3.26. Listas por comprensión en buildConnectionString, paso a paso

>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> params.items()
[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
>>> [k for k, v in params.items()]                1
['server', 'uid', 'database', 'pwd']
>>> [v for k, v in params.items()]                2
['mpilgrim', 'sa', 'master', 'secret']
>>> ["%s=%s" % (k, v) for k, v in params.items()] 3
['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
1 Observe que estamos usando dos variables para iterar sobre la lista params.items(). Éste es otro uso de la asignación multivariable. El primer elemento de params.items() es ('server', 'mpilgrim'), de manera que en la primera iteración de la lista por comprensión, k será 'server' y v será 'mpilgrim'. En este caso estamos ignorando el valor de v y sólo incluimos el valor de k en la lista devuelta, de manera que esta lista acaba siendo equivalente a params.keys().
2 Aquí hacemos lo mismo, pero ignoramos el valor de k, así que la lista acaba siendo equivalente a params.values().
3 Combinar los dos ejemplos anteriores con formato de cadenas sencillo nos da una lista de cadenas que incluye tanto la clave como el valor de cada elemento del diccionario. Esto se parece sospechosamente a la salida del programa. Todo lo que nos queda es juntar los elementos de esta lista en una sola cadena.

Lecturas complementarias sobre listas por comprensión