Tipos de Dados em Python: Guia Prático com Exemplos
Entenda os principais tipos de dados em Python, diferenças entre coleções, mutabilidade, conversões, type hints e exemplos práticos.

Os tipos de dados em Python definem quais valores um objeto pode representar e quais operações fazem sentido para ele. Números permitem cálculos, strings armazenam texto, listas organizam sequências mutáveis e dicionários relacionam chaves a valores. Escolher o tipo adequado torna o código mais claro, previsível e fácil de manter.
Python possui tipagem dinâmica: uma variável não fica presa para sempre a um único tipo. Ao mesmo tempo, a linguagem é fortemente tipada, pois não mistura tipos incompatíveis silenciosamente em operações como somar um número a um texto.
Neste guia, você aprenderá os tipos nativos mais usados, as diferenças entre coleções, como funcionam mutabilidade e referências, quando converter valores e quais erros aparecem com frequência em projetos reais.
O que é um tipo de dado em Python?
Em Python, todo valor é um objeto e todo objeto possui um tipo. O tipo determina o conjunto de operações disponíveis, a forma como o valor se comporta e, em alguns casos, se ele pode ser alterado depois de criado. A documentação do modelo de dados do Python descreve cada objeto por identidade, tipo e valor.
idade = 28 # int
altura = 1.76 # float
nome = "Marina" # str
ativo = True # bool
habilidades = ["Python", "SQL"] # list
O nome da variável é apenas uma referência ao objeto. Essa ideia explica por que duas variáveis podem apontar para a mesma lista e por que alterar a lista por uma delas também aparece na outra.
Tipagem dinâmica e forte
Tipagem dinâmica significa que o tipo pertence ao objeto, não ao nome da variável. O mesmo nome pode referenciar um inteiro e depois uma string. Isso oferece flexibilidade, mas exige nomes claros, validação nas fronteiras do sistema e testes.
resultado = 10
resultado = "processado" # permitido: agora aponta para uma str
Tipagem forte quer dizer que operações incompatíveis não recebem uma conversão arbitrária. "10" + 5 gera TypeError; é necessário escolher conscientemente entre int("10") + 5 e "10" + str(5). Se você ainda está construindo a base, vale revisar a lógica e os fundamentos da programação antes de avançar.
Resumo dos principais tipos de dados
| Categoria | Tipos | Exemplo | Mutável? |
|---|---|---|---|
| Numéricos | int, float, complex | 42, 3.14, 2+3j | Não |
| Booleano | bool | True | Não |
| Texto | str | "Python" | Não |
| Sequências | list, tuple, range | [1, 2], (1, 2) | Só list |
| Conjuntos | set, frozenset | {"a", "b"} | Só set |
| Mapeamento | dict | {"nome": "Ana"} | Sim |
| Binários | bytes, bytearray, memoryview | b"abc" | Depende |
| Ausência | NoneType | None | Não |
A referência oficial de tipos nativos do Python detalha operações, métodos e particularidades de cada grupo. A tabela acima serve como mapa; as próximas seções mostram como decidir na prática.
Tipos numéricos: int, float e complex
int representa números inteiros, positivos ou negativos, sem uma quantidade fixa de bits imposta pela linguagem. float representa números de ponto flutuante e é apropriado para medições e cálculos aproximados. complex guarda uma parte real e outra imaginária.
quantidade = 12
temperatura = 23.5
impedancia = 3 + 4j
print(quantidade * 2) # 24
print(impedancia.real) # 3.0
Valores float não representam exatamente todos os números decimais. Por isso, 0.1 + 0.2 pode não ser exatamente igual a 0.3. Para dinheiro e regras que precisam de precisão decimal controlada, considere decimal.Decimal e defina explicitamente como arredondar.
A divisão com / produz ponto flutuante; // realiza divisão pelo piso; % retorna o resto. Entender essas diferenças evita erros em paginação, lotes e cálculos de intervalo.
Booleanos: bool
bool possui apenas True e False. Comparações produzem booleanos, que controlam condições e laços. Em contextos lógicos, coleções vazias, strings vazias, zero e None são considerados falsos; a maioria dos demais objetos é verdadeira.
itens = []
if not itens:
print("O carrinho está vazio")
maior_de_idade = 21 >= 18 # True
Esse teste de valor lógico não significa que valores diferentes sejam semanticamente iguais. Uma lista vazia pode significar “nenhum item”; None pode significar “informação ainda não fornecida”. Preserve essa distinção no modelo do domínio.
Textos: str
str representa texto Unicode. Strings são sequências imutáveis: você pode acessar caracteres e produzir versões transformadas, mas não alterar um caractere dentro do mesmo objeto.
nome = " Ada Lovelace "
nome_limpo = nome.strip()
print(nome_limpo.upper())
print(f"Olá, {nome_limpo}!")
print(nome_limpo[0]) # A
Métodos como strip(), replace() e lower() retornam novas strings. Para converter entre texto e dados binários, use encode() e decode() com uma codificação explícita, geralmente UTF-8.
Ausência de valor: None
None é o único objeto do tipo NoneType. Ele representa ausência de valor e também é retornado por funções sem um return explícito. Para testá-lo, prefira identidade: valor is None ou valor is not None.
def buscar_usuario(usuario_id):
if usuario_id <= 0:
return None
return {"id": usuario_id}
usuario = buscar_usuario(0)
if usuario is None:
print("Usuário não encontrado")
Sequências: list, tuple e range

Sequências mantêm elementos em uma ordem e permitem acesso por índice, fatiamento e iteração. A diferença decisiva costuma ser a possibilidade de alterar o conteúdo e a intenção que a estrutura comunica.
Lista (list)
Listas são mutáveis, ordenadas e aceitam elementos repetidos. Funcionam bem para uma coleção que cresce, diminui ou muda durante a execução.
tarefas = ["testar", "documentar"]
tarefas.append("publicar")
tarefas[0] = "revisar"
for tarefa in tarefas:
print(tarefa)
Uma lista pode misturar tipos, mas isso nem sempre é uma boa modelagem. Uma coleção homogênea, como list[str], costuma facilitar validação, autocomplete e manutenção.
Tupla (tuple)
Tuplas são sequências imutáveis. Elas representam bem uma estrutura fixa, como coordenadas, uma cor RGB ou múltiplos valores retornados por uma função. A vírgula cria a tupla; uma tupla de um elemento precisa de vírgula: (42,).
coordenada = (-23.55, -46.63)
latitude, longitude = coordenada
def limites(valores):
return min(valores), max(valores)
menor, maior = limites([8, 3, 10])
Intervalo (range)
range representa uma sequência imutável de inteiros sem materializar todos os valores como uma lista. É eficiente para repetições e intervalos previsíveis.
for pagina in range(1, 6):
print(pagina) # 1, 2, 3, 4, 5
pares = range(0, 11, 2)
Conjuntos: set e frozenset
set é uma coleção mutável de elementos únicos e hashable. Ele é indicado para remover duplicidades, testar associação e calcular união, interseção e diferença. Não use conjunto quando a posição ou a repetição tiver significado.
permissoes = {"ler", "editar", "ler"}
print(permissoes) # "ler" aparece uma vez
necessarias = {"ler", "publicar"}
faltantes = necessarias - permissoes
if "editar" in permissoes:
print("Acesso permitido")
frozenset é a variante imutável e pode ser usado como chave de dicionário ou elemento de outro conjunto. Para criar um conjunto vazio, use set(); {} cria um dicionário vazio.
Dicionários: dict
Dicionários são mapeamentos mutáveis de chaves para valores. Cada chave é única e deve ser hashable. Eles são uma escolha natural para registros, configurações, índices e dados semelhantes a JSON.
produto = {
"id": 101,
"nome": "Teclado",
"preco": 249.90,
"estoque": 8,
}
produto["estoque"] -= 1
categoria = produto.get("categoria", "sem categoria")
Acesso com colchetes gera KeyError quando a chave não existe. get() aceita um valor padrão. Escolha entre eles pelo significado: se a ausência representa um erro do contrato, os colchetes tornam a falha explícita; se é uma situação válida, get() pode ser mais adequado.
Dados binários: bytes e bytearray
bytes é uma sequência imutável de bytes; bytearray é mutável. Esses tipos aparecem ao trabalhar com arquivos, imagens, compactação, sockets e protocolos. Eles não devem ser confundidos com str, que representa texto Unicode.
mensagem = "Olá"
dados = mensagem.encode("utf-8")
texto = dados.decode("utf-8")
print(dados) # sequência de bytes
print(texto) # Olá
A fronteira entre texto e bytes deve ser clara: decodifique ao ler uma fonte externa e codifique ao gravar ou transmitir quando o protocolo exigir.
Mutabilidade, identidade e referências

Objetos imutáveis, como int, str e tuple, não mudam seu valor depois de criados. Uma aparente alteração faz a variável apontar para outro objeto. Listas, dicionários e conjuntos são mutáveis: métodos podem alterar o mesmo objeto.
original = ["a", "b"]
apelido = original
apelido.append("c")
print(original) # ["a", "b", "c"]
copia = original.copy()
copia.append("d")
print(original) # continua sem "d"
== compara valores; is compara identidade, isto é, se as referências apontam para o mesmo objeto. Use is principalmente para singletons, como None. Para estruturas aninhadas, uma cópia rasa ainda compartilha objetos internos; a documentação do módulo copy explica a diferença entre cópia rasa e profunda.
Objetos hashable e chaves de dicionário
Um objeto hashable possui um valor de hash estável durante sua vida e pode ser comparado. Esse requisito permite encontrá-lo com eficiência em dicionários e conjuntos. Strings, números e tuplas formadas apenas por elementos hashable normalmente servem como chaves. Listas e dicionários não servem porque podem mudar.
cache = {
("produto", 101): {"nome": "Teclado"},
("produto", 102): {"nome": "Mouse"},
}
# cache[["produto", 101]] # TypeError: list não é hashable
Imutabilidade e hashabilidade são relacionadas, mas não idênticas. Uma tupla que contém uma lista continua não sendo hashable.
Como descobrir e verificar tipos
type(objeto) informa o tipo exato. isinstance(objeto, Tipo) verifica se o objeto pertence àquele tipo ou a uma subclasse, por isso costuma ser mais apropriado em validações. A referência das funções nativas type e isinstance mostra o comportamento oficial.
valor = 10
print(type(valor)) # <class 'int'>
print(isinstance(valor, int)) # True
print(isinstance(valor, (int, float))) # True
Não espalhe verificações de tipo por todo o sistema sem necessidade. Muitas vezes é melhor depender do comportamento esperado, validar entradas nas fronteiras e usar interfaces claras. Em Python e seus principais diferenciais, essa flexibilidade aparece como parte da filosofia prática da linguagem.
Conversão de tipos
Construtores como int(), float(), str(), list() e set() convertem valores quando a transformação é válida. Dados externos devem ser tratados como não confiáveis: faça a conversão dentro de uma validação e produza uma mensagem compreensível.
entrada = " 42 "
try:
quantidade = int(entrada.strip())
except ValueError:
quantidade = 0
print("Quantidade inválida")
int(3.9) trunca a parte decimal; não arredonda. bool("False") retorna True porque a string não está vazia. Para interpretar texto booleano, defina valores aceitos explicitamente.
def converter_booleano(valor: str) -> bool:
normalizado = valor.strip().lower()
if normalizado in {"true", "1", "sim"}:
return True
if normalizado in {"false", "0", "nao", "não"}:
return False
raise ValueError("Valor booleano inválido")
Type hints mudam o tipo em tempo de execução?
Anotações de tipo documentam a intenção e ajudam editores, linters e verificadores estáticos. Por padrão, elas não impedem que outro tipo seja passado em tempo de execução. A documentação oficial de typing deixa claro que o runtime do Python não aplica as anotações.
def calcular_total(precos: list[float]) -> float:
return sum(precos)
total = calcular_total([19.90, 30.00])
Type hints são especialmente úteis em funções públicas, modelos de domínio e integrações. Eles complementam testes e validação; não substituem nenhum dos dois. À medida que o projeto cresce, também facilitam a passagem de estruturas simples para classes, tema aprofundado no guia de Python para iniciantes.
Como escolher a coleção correta
| Necessidade | Tipo indicado | Motivo |
|---|---|---|
| Manter ordem e alterar elementos | list | Sequência mutável |
| Representar uma estrutura fixa | tuple | Sequência imutável |
| Garantir unicidade ou testar associação | set | Elementos únicos e busca eficiente |
| Relacionar identificadores a valores | dict | Mapeamento por chave |
| Iterar por uma faixa de inteiros | range | Não materializa toda a lista |
| Usar um conjunto como chave | frozenset | Conjunto imutável e hashable |
Não escolha apenas pelo que “funciona”. Pense na regra que a estrutura comunica. Uma tupla sinaliza estabilidade; um conjunto informa que ordem e repetição não importam; um dicionário torna o acesso por nome explícito.
Exemplo prático: tratando dados de uma API
Respostas JSON normalmente chegam ao Python como dicionários, listas, strings, números, booleanos e None. Antes de usar esses dados, confirme campos obrigatórios e converta valores que o contrato permite receber como texto.
def normalizar_produto(dados: dict) -> dict:
nome = str(dados.get("nome", "")).strip()
if not nome:
raise ValueError("O nome é obrigatório")
try:
preco = float(dados["preco"])
estoque = int(dados.get("estoque", 0))
except (KeyError, TypeError, ValueError) as erro:
raise ValueError("Preço ou estoque inválido") from erro
categorias_brutas = dados.get("categorias") or []
if not isinstance(categorias_brutas, list):
raise ValueError("Categorias devem formar uma lista")
categorias = {
str(item).strip().lower()
for item in categorias_brutas
if str(item).strip()
}
return {
"nome": nome,
"preco": preco,
"estoque": estoque,
"categorias": sorted(categorias),
"ativo": estoque > 0,
}
O exemplo usa dict para o registro, str para normalizar texto, float e int para valores numéricos, set para eliminar categorias repetidas, list na saída serializável e bool para o status. Em uma aplicação real, bibliotecas de validação e modelos de domínio podem formalizar esse contrato.
Se você pretende transformar esse conhecimento em serviço web, veja também como construir uma API RESTful em Python com Flask. Para consolidar o aprendizado, escolha um dos projetos backend para praticar e modele os dados antes de escrever as rotas.
Erros comuns com tipos de dados
- Usar float para dinheiro sem avaliar precisão: regras financeiras normalmente pedem decimal e arredondamento definido.
- Confundir is com ==: identidade e igualdade respondem a perguntas diferentes.
- Criar conjunto vazio com {}: isso cria um dicionário; use
set(). - Converter entrada sem tratar falha:
int("dez")geraValueError. - Supor que bool(“False”) é falso: qualquer string não vazia é verdadeira.
- Compartilhar lista sem perceber: uma atribuição não cria cópia.
- Usar argumento mutável como padrão: a mesma lista pode ser reutilizada entre chamadas.
- Retornar tipos inconsistentes: ora lista, ora
None, sem contrato claro, aumenta verificações no consumidor. - Misturar bytes e str: codificação precisa ser explícita nas fronteiras.
# Evite um objeto mutável criado uma única vez na definição
def adicionar_item(item, itens=None):
if itens is None:
itens = []
itens.append(item)
return itens
Em muitos casos, o melhor caminho é definir um contrato: quais tipos entram, quais saem, quais ausências são válidas e quais conversões podem acontecer. Isso também prepara o código para uma futura atuação como desenvolvedor backend, onde dados externos são parte constante do trabalho.
Exercícios para praticar
- Leia uma string com vários nomes separados por vírgula, remova espaços e produza uma lista sem itens vazios.
- Converta a lista em conjunto para descobrir nomes únicos e depois ordene o resultado.
- Crie um dicionário que conte quantas vezes cada nome aparece.
- Modele um produto com nome, preço, quantidade e categorias; valide cada campo.
- Compare uma atribuição, uma cópia rasa e uma cópia profunda em uma lista de dicionários.
- Escreva uma função anotada que receba
list[float]e retorne média ouNonequando estiver vazia.
Execute os exemplos, altere entradas e tente prever o resultado antes de rodar. Essa prática revela diferenças que a leitura isolada não mostra.
Perguntas frequentes
Qual é a diferença entre list e tuple?
list é mutável e indicada para coleções que mudam. tuple é imutável e comunica uma estrutura fixa. Ambas mantêm ordem, permitem repetição e suportam acesso por índice.
Python converte tipos automaticamente?
Algumas operações numéricas promovem valores, como somar int e float. Porém, Python não transforma automaticamente uma string numérica em inteiro para somá-la. Conversões importantes devem ser explícitas.
Quando usar set em vez de list?
Use set quando unicidade, associação, união ou interseção forem centrais e a posição não importar. Use list quando a ordem, repetição ou acesso por índice fizerem parte da regra.
None, False e zero são iguais?
Não. Todos são falsos em um teste lógico, mas representam conceitos distintos: ausência, valor booleano falso e quantidade numérica zero. Modele essa diferença e use is None quando quiser testar ausência.
Type hints são obrigatórios?
Não são obrigatórios para executar o programa. Entretanto, melhoram documentação, análise estática e colaboração, sobretudo em bases de código maiores. A equipe pode defini-los como parte do padrão do projeto.
Conclusão
Dominar os tipos de dados em Python significa ir além de decorar nomes. Você precisa reconhecer a intenção de cada estrutura, saber quais objetos são mutáveis, entender referências e fazer conversões com validação.
Comece com os tipos mais frequentes — int, float, str, bool, list, tuple, set, dict e None — e aplique-os em pequenos projetos. A escolha correta reduz estados inválidos, expressa melhor as regras do domínio e cria uma base sólida para APIs, automação, análise de dados e orientação a objetos.