9. Tuplas

Una tupla es una secuencia de valores agrupados que en general se usan como si fueran un único valor y que por su naturaleza debiesen ir juntos. En Python el tipo de datos que representa a las tuplas se llama "tuple" siendo su característica principal ser una estructura tipo conjunto inmutable.

Que un conjunto de datos sea inmutable quiere decir que una vez creada o declarada con sus valores estos no pueden ser modificados.

Las "tuplas" en otros lenguajes de programación reciben el nombre de registros y probablemente este nombre es mucho más común para encontrarlo como referencia, por lo que conviene realizar esta analogía.

Una tupla es creada poniendo los valores separados por comas y entre paréntesis.

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

lenguajes = ("Python", "Rust")
print(lenguajes)
print(type(lenguajes))  

Salida

('Python', 'Rust')
<class 'tuple'>

Observar los elementos de contiene esta tupla (lenguajes) están entre paréntesis, marcando una diferencia importante con una lista que se declara entre corchetes ([]).

9.1. Accediendo a los elementos

Existen diversas formas de como acceder a las "tuplas" una de ellas es lo que se conoce como desempaquetar (unpack en inglés). Esta técnica consiste en que los valores existentes de una tupla pueden ser recuperados asignando a la tupla la misma cantidad de variables que cantidad de elementos de la "tupla".

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

lenguajes = ("Python", "Rust")
python, rust = lenguajes
print(python)
print(rust)

Salida

Python
Rust

Específicamente este caso presenta una tupla con dos elementos cuyos elementos son asociado a dos variables. La asignación es elemento a elemento, posición a posición, por lo que la primera variable declarada ("python") se le asigna el primer elemento de la tupla y la segunda variable declarada ("rust") le corresponde el segundo elemento de la tupla.

La cantidad de variables a asignar dependerá de la cantidad de elementos de la tupla y se debe tener cuidado porque si se intenta desempaquetar una cantidad incorrecta de valores generará un error de excepción.

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

lenguajes = ("Python", "Rust")
python, rust, otro = lenguajes
print(python)
print(rust)

Ocurre un error de excepción:

Traceback (most recent call last):
File "tuplas.py", line 5, in <module>
python, rust, otro = lenguajes
ValueError: not enough values to unpack (expected 3, got 2)

La cantidad de variables declaradas que esperan un valor es mayor a la cantidad de elementos que existen en la tupla.

Una segunda forma de extraer valores desde una tupla es a través de declarar índices. Esto es del mismo modo del que podemos acceder a valores desde las listas.

Ejemplo

lenguajes = ("Python", "Rust")
python = lenguajes[0]
print(python)

Salida

Python

De acuerdo a la declaración para la variable "python" el valor obtenido es la posición cero de la tupla que es el "string" 'Python'.

9.2. Modificar elementos

Como ya ha sido expresado en un punto anterior, las tuplas son estructuras inmutables, por lo que sus elementos no pueden ser modificados y en el caso de intentar modificar cualquier elemento del conjunto, se obtendrá un error de excepción.

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

lenguajes = ("Python", "Rust")
lenguajes[0] = "C++"
print(lenguajes)

Salida

Traceback (most recent call last):
  File "tuplas4.py", line 5, in <module>
    lenguajes[0] = "C++"
TypeError: 'tuple' object does not support item assignment

Python al querer modificar el objeto de tipo "tupla" devuelve la excepción 'el objeto tupla no admite la re-asignación a un elemento', siendo una declaración prohibida por lenguaje.

9.3. Recorrer tuplas

La tuplas al ser un objeto tipo conjunto lo hace un elemento iterable, por lo que es posible recorrerlo a través de una estructura repetitiva como un ciclo "for" o "while".

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

lenguajes = ("Python", "Rust", "C++", "Java", "Javascript", "Go")

for item in lenguajes:
    print(item)

item = 0
while item < len(lenguajes):
    print(lenguajes[item])
    item = item + 1

Salida

Python
Rust
C++
Java
Javascript
Go
Python
Rust
C++
Java
Javascript
Go

Las formas de recorrido de las tuplas es igual al definido por un objeto de tipo "list", por lo que para un ciclo "for" basta con definir una variable que permita iterar a través de ella el conjunto de datos establecido, mientras que la estructura "while" se debe declarar la condición y un iterador tipo contador que debe ser incrementado para ser accedido por medio de un indice.

9.4. Comparación de dos tuplas

9.4.1. Igualdad

Serán iguales dos tuplas si poseen el mismo tamaño y cada uno de sus elementos correspondientes tienen el mismo valor.

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*


a = (1, 2)
b = (int(3 / 2), 1 + 1)

if a == b:
    print("Son iguales")
else:
    print("Son distintas")
    
c = (6, 1)
d = (6, 2)

if c == d:
    print("Son iguales")
else:
    print("Son distintas")
    

Salida

Son iguales
Son distintas

Para el primer caso se dirá que las tuplas son idénticas ('Son iguales'). El motivo es que a pesar de que en declaración no sean iguales ambas tuplas, sí lo son en resultado. El primer elemento de la tupla "b" realiza una división de enteros cuyo valor es idéntico al primer elemento de la tupla "a" y el segundo elemento de la tupla "b" también realiza una operación (suma) y el resultado es igual al segundo elemento de la tupla "a".

Caso contrario se da para el segundo caso de la comparación (tuplas c y d). Acá el resultado es claramente distinto porque los segundos elementos de ambas tuplas son diferentes.

9.4.2. Menor o mayor

Se puede determinar si una tupla es menor que otra si se utiliza lo que se denomina orden lexicografico. Para esto se determina que si los elementos en la primera posición de ambas tuplas son distintos se comparan y determinan si el valor es mayor o menor.

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

a = (1, 4, 7)
b = (2, 0, 0, 1)

if a < b:
    print("a es menor que b")
else:
    print("b es menor que a")

La tupla "a" es menor que "b" ya que el primer elemento de la tupla "a" es uno (1) y el primer elemento de la tupla "b" es dos (2) entonces '1 < 2'.

Para el caso en que los elementos en la primera posición sean iguales se comparan los siguientes valores uno a uno hasta lograr una diferencia y establecer una determinación (mayor o menor).

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

a = (8, 4, 7)
b = (8, 0, 0, 1)

if a < b:
    print("a es menor que b")
else:
    print("b es menor que a")

Los primeros elementos de ambas tuplas son iguales, pero el segundo elemento de la tupla "b" es cero (0) y el segundo elemento de la tupla "a" es cuatro (4) entonces 4 es mayor que 0 (0 < 4) por lo que "b" es menor que "a".

Hay que prestar atención con este ejemplo porque la tupla "b" contiene un elemento más que la tupla "a". Intuitivamente se puede pensar que "b" sería mayor a "a" por la cantidad de elementos, pero esto no resulta ser cierto ya que el resultado de la condición lo determina el valor de acuerdo a su posición y no la cantidad de elementos que posee un conjunto.

De lo anterior también se bueno saber que si los elementos respectivos siguen siendo iguales hasta que se le acaban los elementos para comparar a una tupla, entonces a la tupla de menor elementos se le es considerada menor.

Para el caso de las cadenas de strings se utiliza para establecer el criterio de menor o mayor el orden alfabético:

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

a = ("avión", "camión", "taxi")
b = ("bus", "camioneta")

if a < b:
    print("a es menor que b")
else:
    print("b es menor que a")

Salida

a es menor que b

Como 'avión' alfabéticamente está antes que 'bus' el resultado de comparación de ambos conjuntos es que la tupla "a" es menor a la tupla "b".

9.5. Algunos usos

Las tuplas se recomienda usar siempre y cuando sea necesario agrupar valores que generalmente sean conceptos del mundo real y que agrupan información sobre ellos que no es posible modificar. De una manera más concisa es que si se está definiendo un conjunto constante de valores y todo lo que va a hacer con él es iterar, usar una tupla en lugar de una lista.

Ejemplo

partido1 = ('Universidad de Chile', 'Liverpool')

Es una muy buena idea utilizar las tuplas como estrategia de abordar la complicidad de las fechas. La tupla puede estar constituida por el año, el mes y el día.

Ejemplo

hoy = (2020, 1, 19)
ayer = (2020, 1, 18)

Claramente si evaluamos que fecha es menor u ocurrió antes, debemos decir que ayer (ayer < hoy)

Otro ejemplo de uso práctico de tuplas es almacenar datos de una persona (nombre, su rut y su fecha de nacimiento)

Ejemplo

#!/usr/bin/env python3
# -*- coding:utf-8 *-*

persona = ("Pepito", "Pepone", (1999, 1, 30))
nombre, apellido, fecha_nacimiento = persona
print("El señor {0} {1} nació el {2}".format(nombre,
                                             apellido,
                                             fecha_nacimiento))

Salida

El señor Pepito Pepone nació el (1999, 1, 30)

9.6. Diferencia entre tuplas y listas

Las listas y tuplas tienen varias similitudes y es importante reconocer sus diferencias para poder utilizar los objetos correctos en instancias determinadas.

Algunas diferencias son:

  • Las tuplas son inmutables y las listas son variables

  • No puede agregar elementos a una tupla, no tienen un método para agregar o extender, las listas si.

  • No puede eliminar elementos de una tupla y las listas tienen método de "del" o "pop" para hacerlo.

  • Las tuplas son más rápidas que las listas.

  • El uso de tuplas hace que el código sea más seguro si se 'protege contra escritura' ya que los datos que no necesitan ser cambiados. Usar una tupla en lugar de una lista es como tener una afirmación implícita de que estos datos son constantes y que se requiere un pensamiento especial (y una función específica) para anular eso.

  • Algunas tuplas pueden usarse como claves de diccionario (específicamente, tuplas que contienen valores inmutables como cadenas, números u otro dato constante). Por otro lado, las listas nunca pueden usarse como claves de diccionario porque las listas son mutables.