Tupla em Python: O que É e Como Funciona | Python Brasil
Guia completo sobre tuplas em Python: imutabilidade, named tuples, desempacotamento, *args, pattern matching e quando usar em vez de listas.
O que é uma Tupla?
Uma tupla é uma estrutura de dados imutável e ordenada em Python. Ela funciona de forma similar a uma lista, mas uma vez criada, seus valores não podem ser alterados. Tuplas são definidas usando parênteses () ou simplesmente separando valores por vírgulas — os parênteses são opcionais na maioria dos contextos.
A imutabilidade não é uma limitação acidental: é uma garantia intencional que transmite a intenção de que aqueles dados formam um registro fixo, como uma coordenada, uma configuração ou o retorno de uma função.
Como criar e usar
# Formas de criar tuplas
coordenadas = (23.5505, -46.6333) # com parênteses
cores = 'vermelho', 'verde', 'azul' # sem parênteses (tuple packing)
mista = (1, 'Python', 3.14, True)
# Tupla com um único elemento — a vírgula é obrigatória
singleton = (42,) # tupla com um elemento
nao_tupla = (42) # apenas o inteiro 42, não uma tupla
print(type(singleton)) # <class 'tuple'>
print(type(nao_tupla)) # <class 'int'>
# Tupla vazia
vazia = ()
vazia2 = tuple()
# Convertendo outros iteráveis
from_lista = tuple([1, 2, 3])
from_str = tuple('abc') # ('a', 'b', 'c')
Métodos disponíveis
Tuplas têm apenas dois métodos — a imutabilidade elimina os demais:
t = (1, 2, 3, 2, 4, 2, 5)
# count — quantas vezes um valor aparece
print(t.count(2)) # 3
# index — posição da primeira ocorrência
print(t.index(3)) # 2
print(t.index(2)) # 1 (primeira ocorrência)
# index com start e stop (opcional)
print(t.index(2, 2)) # 3 (busca a partir do índice 2)
print(t.index(2, 4)) # 5 (busca a partir do índice 4)
Tupla vs Lista: quando usar cada uma
import sys
lista = [1, 2, 3, 4, 5]
tupla = (1, 2, 3, 4, 5)
# Tuplas ocupam menos memória
print(sys.getsizeof(lista)) # 120 bytes (aprox.)
print(sys.getsizeof(tupla)) # 80 bytes (aprox.)
# Tuplas são mais rápidas para criar e iterar
import timeit
print(timeit.timeit('(1,2,3,4,5)', number=10_000_000)) # ~0.05s
print(timeit.timeit('[1,2,3,4,5]', number=10_000_000)) # ~0.25s
# A grande diferença: imutabilidade
lista[0] = 99 # OK
# tupla[0] = 99 # TypeError: 'tuple' object does not support item assignment
# Use tupla quando:
# - os dados representam um registro fixo (coordenadas, cores RGB, etc.)
# - precisa usar como chave de dicionário
# - quer sinalizar para outros devs que os dados não devem mudar
Tupla como tipo hashable (chave de dicionário)
Como tuplas são imutáveis, elas são hashable e podem ser usadas como chaves de dicionário — algo que listas não podem fazer:
# Coordenadas como chaves de dicionário
mapa_cidades = {
(-23.5505, -46.6333): 'São Paulo',
(-22.9068, -43.1729): 'Rio de Janeiro',
(-30.0346, -51.2177): 'Porto Alegre',
}
lat, lon = -23.5505, -46.6333
print(mapa_cidades[(lat, lon)]) # São Paulo
# Cache de resultados com tuple como chave
cache = {}
def fibonacci(n):
if n in cache:
return cache[n]
if n <= 1:
resultado = n
else:
resultado = fibonacci(n - 1) + fibonacci(n - 2)
cache[n] = resultado
return resultado
# Ou usando tupla como chave composta
grade_resultado = {}
for linha in range(5):
for coluna in range(5):
grade_resultado[(linha, coluna)] = linha * coluna
print(grade_resultado[(3, 4)]) # 12
Desempacotamento (tuple unpacking) em detalhes
O desempacotamento de tuplas é uma das funcionalidades mais expressivas do Python:
# Desempacotamento básico
ponto = (10, 20, 30)
x, y, z = ponto
print(x, y, z) # 10 20 30
# Trocar valores sem variável temporária
a, b = 1, 2
a, b = b, a
print(a, b) # 2 1
# Ignorar valores com _
_, segundo, _ = (1, 2, 3)
print(segundo) # 2
# Starred expressions (*) — captura múltiplos valores
primeiro, *meio, ultimo = (1, 2, 3, 4, 5)
print(primeiro) # 1
print(meio) # [2, 3, 4] — note: retorna lista, não tupla
print(ultimo) # 5
# Starred no início
*inicio, penultimo, ultimo = range(10)
print(inicio) # [0, 1, 2, 3, 4, 5, 6, 7]
# Desempacotamento em loop
pontos = [(0, 0), (1, 2), (3, 4)]
for x, y in pontos:
print(f"({x}, {y})")
# Desempacotamento aninhado
(a, b), c = (1, 2), 3
print(a, b, c) # 1 2 3
Tuplas em assinaturas de função (*args)
# *args captura argumentos posicionais como uma tupla
def somar(*numeros):
print(type(numeros)) # <class 'tuple'>
return sum(numeros)
print(somar(1, 2, 3)) # 6
print(somar(1, 2, 3, 4, 5)) # 15
# Desempacotando uma tupla ao chamar uma função
args = (2, 3)
print(pow(*args)) # 8 (equivalente a pow(2, 3))
coordenadas = (-23.5505, -46.6333)
def mostrar_ponto(lat, lon):
print(f"Latitude: {lat}, Longitude: {lon}")
mostrar_ponto(*coordenadas) # desempacota a tupla como argumentos
# Retornando múltiplos valores (Python retorna uma tupla)
def dividir(a, b):
quociente = a // b
resto = a % b
return quociente, resto # retorna tupla (sem precisar de parênteses)
q, r = dividir(17, 5)
print(f"Quociente: {q}, Resto: {r}") # Quociente: 3, Resto: 2
Named Tuples — tuplas com campos nomeados
Named tuples adicionam nomes aos campos, tornando o código mais legível sem o overhead de uma classe completa:
from collections import namedtuple
# namedtuple clássico
Ponto = namedtuple('Ponto', ['x', 'y'])
p = Ponto(10, 20)
print(p.x, p.y) # 10 20 — acesso por nome
print(p[0], p[1]) # 10 20 — acesso por índice (ainda funciona)
print(p) # Ponto(x=10, y=20) — repr útil
# É uma tupla de verdade
print(isinstance(p, tuple)) # True
Endereco = namedtuple('Endereco', ['rua', 'numero', 'cidade', 'estado'])
ende = Endereco('Av. Paulista', 1000, 'São Paulo', 'SP')
print(f"{ende.rua}, {ende.numero} — {ende.cidade}/{ende.estado}")
# _replace — cria uma nova instância com campos alterados (imutável!)
novo_ende = ende._replace(numero=2000)
print(novo_ende)
# _asdict — converte para dicionário
print(dict(ende._asdict()))
typing.NamedTuple — versão moderna com type hints
from typing import NamedTuple
from datetime import date
class Produto(NamedTuple):
nome: str
preco: float
estoque: int = 0 # campo com valor padrão
criado_em: date = None # campo opcional
p = Produto('Café Premium', 28.90, estoque=100)
print(p.nome) # Café Premium
print(p.estoque) # 100
print(p.criado_em) # None
# Suporta docstrings e métodos (leitura apenas)
class Coordenada(NamedTuple):
"""Representa um ponto geográfico."""
latitude: float
longitude: float
def distancia_origem(self) -> float:
return (self.latitude ** 2 + self.longitude ** 2) ** 0.5
def __str__(self) -> str:
return f"({self.latitude:.4f}, {self.longitude:.4f})"
sp = Coordenada(-23.5505, -46.6333)
print(sp) # (-23.5505, -46.6333)
print(sp.distancia_origem()) # 52.37...
Pattern Matching com tuplas (Python 3.10+)
O structural pattern matching (PEP 634) funciona de forma natural com tuplas:
# Python 3.10+
def processar_evento(evento):
match evento:
case ('clique', x, y):
print(f"Clique em ({x}, {y})")
case ('tecla', 'Enter'):
print("Enter pressionado")
case ('tecla', tecla):
print(f"Tecla pressionada: {tecla}")
case ('scroll', direcao, quantidade) if direcao in ('cima', 'baixo'):
print(f"Scroll {direcao}: {quantidade}px")
case _:
print("Evento desconhecido")
processar_evento(('clique', 100, 200)) # Clique em (100, 200)
processar_evento(('tecla', 'Enter')) # Enter pressionado
processar_evento(('scroll', 'cima', 3)) # Scroll cima: 3px
# Pattern matching com namedtuple
from typing import NamedTuple
class Ponto2D(NamedTuple):
x: float
y: float
def classificar_ponto(p):
match p:
case Ponto2D(x=0, y=0):
return "origem"
case Ponto2D(x=0, y=_):
return "eixo Y"
case Ponto2D(x=_, y=0):
return "eixo X"
case Ponto2D(x=x, y=y) if x == y:
return "diagonal principal"
case _:
return "ponto geral"
print(classificar_ponto(Ponto2D(0, 0))) # origem
print(classificar_ponto(Ponto2D(3, 3))) # diagonal principal
Erros comuns
# Erro 1: esquecer a vírgula no singleton
nao_tupla = (42) # int, não tupla
tupla_ok = (42,) # tupla com um elemento
# Erro 2: tentar modificar
t = (1, 2, 3)
# t[0] = 10 # TypeError
# Mas se a tupla contém objetos mutáveis, eles podem mudar:
t_mutavel = ([1, 2], [3, 4])
t_mutavel[0].append(99) # OK — a lista dentro muda
print(t_mutavel) # ([1, 2, 99], [3, 4])
# A tupla em si não mudou — ainda referencia as mesmas duas listas
# Erro 3: desempacotamento com número errado de variáveis
a, b = (1, 2, 3) # ValueError: too many values to unpack
Boas práticas
- Use tuplas para dados que semanticamente formam um registro imutável (coordenadas, cores, configurações).
- Prefira
typing.NamedTupleacollections.namedtupleem código novo — oferece type hints e IDE support. - Use tuplas como chaves de dicionário para mapeamentos multidimensionais.
- Aproveite o desempacotamento com
*para código mais expressivo. - Em funções que retornam múltiplos valores, considere
NamedTuplese os valores têm semântica distinta.
Termos Relacionados
- Dicionário — Tuplas podem ser chaves de dicionários por serem hashable
- List Comprehension — Para criar listas (mutáveis) de forma concisa
- Classe — Alternativa mais estruturada quando os dados têm comportamentos