SkillsTecnológicas
Menu
Back-end

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.

Marcos RodriguesPublicado em 4 de outubro de 2024Atualizado em 22 de agosto de 202613 min de leitura
Desenvolvedor estuda representações visuais de diferentes tipos de dados em Python

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

CategoriaTiposExemploMutável?
Numéricosint, float, complex42, 3.14, 2+3jNão
BooleanoboolTrueNão
Textostr"Python"Não
Sequênciaslist, tuple, range[1, 2], (1, 2)Só list
Conjuntosset, frozenset{"a", "b"}Só set
Mapeamentodict{"nome": "Ana"}Sim
Bináriosbytes, bytearray, memoryviewb"abc"Depende
AusênciaNoneTypeNoneNã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

Objetos representam as diferenças entre lista, tupla, conjunto e dicionário em Python
Listas priorizam uma sequência mutável, tuplas registram uma sequência imutável, conjuntos trabalham com elementos únicos e dicionários relacionam chaves a valores.

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

Contêineres conectados representam referências compartilhadas, mutação e cópia de objetos em Python
Duas variáveis podem apontar para o mesmo objeto mutável. Alterar esse objeto afeta ambas as referências; criar uma cópia independente muda esse comportamento.

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

NecessidadeTipo indicadoMotivo
Manter ordem e alterar elementoslistSequência mutável
Representar uma estrutura fixatupleSequência imutável
Garantir unicidade ou testar associaçãosetElementos únicos e busca eficiente
Relacionar identificadores a valoresdictMapeamento por chave
Iterar por uma faixa de inteirosrangeNão materializa toda a lista
Usar um conjunto como chavefrozensetConjunto 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") gera ValueError.
  • 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

  1. Leia uma string com vários nomes separados por vírgula, remova espaços e produza uma lista sem itens vazios.
  2. Converta a lista em conjunto para descobrir nomes únicos e depois ordene o resultado.
  3. Crie um dicionário que conte quantas vezes cada nome aparece.
  4. Modele um produto com nome, preço, quantidade e categorias; valide cada campo.
  5. Compare uma atribuição, uma cópia rasa e uma cópia profunda em uma lista de dicionários.
  6. Escreva uma função anotada que receba list[float] e retorne média ou None quando 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.