Cap. 9 - Tuplas

9.1) Las tuplas se usan para agrupar datos

Ya hemos visto que podemos agrupar pares de valores con sólo rodearlos entre paréntesis. Por ejemplo:

		>>> año_nacimiento = ("Novak Djokovic", 1987)

Este es un ejemplo de estructura de datos - un mecanismo para agrupar y organizar datos para facilitar el uso de los mismos.

El par es un ejemplo de tupla. Generalizando el concepto de par, una tupla puede utilizarse para agrupar cualquier cantidad de items en un solo valor compuesto. Sintácticamente, una tupla es una secuencia de valores separados por comas. Aunque no es necesario, es convencional encerrar a las tuplas entre paréntesis.

		>>> julia = ("Julia", "Roberts", 1967, "Duplicity", 2009, "Actress", "Atlanta, Georgia")

		>>> brasil_campeon = 1958, 1962, 1970, 1994, 2002
		>>> brasil_campeon
		(1958, 1962, 1970, 1994, 2002)

Las tuplas son útiles para representar lo que otros lenguajes llaman registros (records) - cierta información relacionada que debería guardarse junta, como los registros de un estudiante. No hay una descripción de lo que cada uno de esos campos significa, pero podemos deducirlo. Una tupla nos permite "empaquetar" junta a cierta cantidad de información relacionada y usar ese paquete como una cosa única.

Las tuplas soportan los mismos operadores de secuencia que los strings. El operador índice selecciona un elemento de la tupla:

		>>> julia[2]
		1967

Pero si tratamos de usar asignación de items para modificar uno de los elementos de la tupla, se nos devolverá un mensaje de error:

		>>> julia[0] = "X"
		TypeError: 'tuple' object does not support item assignment

Es decir que, igual que los strings, las tuplas son inmutables. Una vez que Python ha creado una tupla en memoria, ya no puede cambiarse.

Por supuesto, aunque no podemos modificar los elementos de una tupla, sí podemos crear a partir de julia una nueva tupla que contenga información modificada. Para construir la nueva tupla, es conveniente poder trocear (slice) partes de la vieja tupla y combinarlas para formar una nueva. Así que si julia tiene un nuevo film (reciente) podríamos cambiar su variable para que referencia una nueva tupla que incluye información de la original:

		>>> julia = julia[:3] + ("Eat Pray Love", 2010) + julia[5:]
		>>> julia
		("Julia", "Roberts", 1967, "Eat Pray Love", 2010, "Actress", "Atlanta, Georgia")

Para crear una tupla con un solo elemento (aunque no parece algo que tuviera mucho sentido hacer), tenemos que incluir la coma final, porque sin ella, Python tratará al (5) del ejemplo que sigue como a un entero entre paréntesis:

		>>> tup = (5,)
		>>> type(tup)
		<class 'tuple'>
		>>> x = (5)
		>>> type(x)
		<class 'int'>

9.2) Asignación de tuplas

Python tiene una poderosa funcionalidad de asignación de tuplas que permite copiar los valores de una tupla completa a una tupla de nombres de variables del mismo tamaño - ya lo habíamos visto para pares, pero vale para tuplas de cualquier tamaño. Un ejemplo:

		(name, surname, b_year, movie, m_year, profession, b_place) = julia

Esto hace el equivalente a 7 sentencias de asignación, todo en una simple línea. Es necesario que el número de variables a la izquierda coincida con la cantidad de elementos en la tupla.

Una forma de pensar en una asignación de tuplas es como un empaquetamiento/desempaquetamiento (packing/unpacking) de la tupla.

En el empaquetado (packing) de una tupla, se empaquetan los variables de la derecha en una sola tupla definida como variable a la izquierda del igual:

		>>> b = ("Bob", 19, "CS")    # empaquetamiento (packing) de la tupla

En el desempaquetado (unpacking), los valos de la tripleta de la derecha se "desempaquetan" en 3 variables a la izquierda:

		>>> b = ("Bob", 19, "CS")
		>>> (nombre, edad, estudios) = b    # desempaquetamiento (unpacking) de la tupla
		>>> nombre
		'Bob'
		>>> edad
		19
		>>> estudios
		'CS'

De vez en cuando es conveniente intercambiar el valor de dos variables (hacer un swap). Con sentencias de asignación tradicional, tenemos que usar una variable temporal. Por ejemplo, para hacer el swap de a y b haríamos así:

		temp = a
		a = b
		b = temp

La asignación de tuplas resuelve este problema de un modo sencillísimo:

		(a, b) = (b, a)

El lado izquierdo es tupla de variables, mientras que el derecho es tupla de valores. Cada valor es asignado a su respectiva variable. Todas las expresiones en el lado derecho son evaluadas antes de las asignaciones. Esta característica hace a la asignación de tuplas una funcionalidad muy versátil.

Naturalmente, la cantidad de variables en el lado izquierdo y el número de variables en el derecho tiene que ser el mismo.

		>>> (a, b, c, d) = (1, 2, 3)
		ValueError: need more than 3 values to unpack

9.3) Tuplas como valores de retorno

Las funciones sólo pueden retornar un único valor, pero si hacemos que ese valor sea una tupla, podemos agrupar efectivamente todos los valores que necesitemos devolver. Esto es muy útil - es frecuente querer conocer los goles a favor y en contra en un partido de fútbol, o la media y la desviación estándar de una muestra estadística, o el año, mes y día de un evento, o el número de conejos y de lobos que están vivos en una isla en un cierto momento.

Un ejemplo: escribiremos una función que devuelve a la vez el área y el perímetro de un círculo de radio r:

def perimetro_area_circulo(r):
    """ Retorna (perímetro, área) de un círculo de radio r """
    perimetro = 2 * math.pi * r
    area = math.pi * r * r
    return (perimetro, area)

9.4) Componibilidad de estructuras de datos

Vimos en un capítulo anterior que podríamos hacer una lista de pares, y vimos ejemplos en que uno de los items de una tupla era él mismo una lista:

def print_estudiantes():
    estudiantes = [
        ("Juan", ["Informática", "Física"]),
        ("Dani", ["Matemáticas", "Informática", "Estadística"]),
        ("Jess", ["Informática", "Contabilidad", "Economía", "Administración"]),
        ("Sarah", ["Informática", "Contabilidad", "Economía", "Filosofía"]),
        ("Zaira", ["Sociología", "Economía", "Derecho", "Estadísticas", "Música"])]

Los items de tuplas también pueden ser tuplas ellos mismos. Por ejemplo, podríamos mejorar la información sobre cada una de nuestras estrellas de cine guardando la fecha completa de nacimiento en vez de sólo el año, y podríamos tener una lista de las películas que hicieron con sus fechas respectivas, etc. Algo así:

julia_more_info = ( ("Julia", "Roberts"), (8, "October", 1967),
                     "Actress", ("Atlanta", "Georgia"),
                     [ ("Duplicity", 2009),
                       ("Notting Hill", 1999),
                       ("Pretty Woman", 1990),
                       ("Erin Brockovich", 2000),
                       ("Eat Pray Love", 2010),
                       ("Mona Lisa Smile", 2003),
                       ("Oceans Twelve", 2004) ])

Observa en este caso que la tupla tiene 5 elementos - pero cada uno de esos puede ser a su vez otra tupla, una lista, un string, o cualquier otra clase de valor de Python. Esta propiedad se conoce como heterogeneidad, lo cual simplemente significa que puede estar compuesta de elementos de distintos tipos.

9.5) Glosario

9.6) Ejercicios

1) No hemos dicho hasta ahora si se puede o no pasar tuplas como argumentos a funciones. Construir un pequeño ejemplo Python para verificar si es posible, y anotar tus conclusiones.

 

2) ¿Es un par una generalización de una tupla, o una tupla una generalización de un par?

 

3) ¿Es un par un tipo de tupla, o una tupla un tipo de par?