Voltar ao Glossario
Glossario Python

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.NamedTuple a collections.namedtuple em 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 NamedTuple se 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