uuid no Python: IDs únicos e ordenáveis

Publicado em: 30/07/2026
Tempo de leitura: 8 minutos
Código digital representando identificadores UUID únicos e ordenáveis no Python

Identificadores aparecem em usuários, pedidos, arquivos, eventos, mensagens, registros de auditoria e sistemas distribuídos. Uma sequência numérica funciona dentro de um único banco, mas exige coordenação quando vários serviços criam dados ao mesmo tempo. O módulo uuid no Python oferece objetos imutáveis de 128 bits que podem ser gerados sem uma autoridade central e transportados como texto, bytes ou inteiro.

Neste guia, você aprenderá quando usar UUIDv4, UUIDv5, UUIDv6 e UUIDv7, por que UUIDv1 pode expor informações, como validar strings, armazenar valores em bancos, ordenar IDs e evitar confundir unicidade com segurança. O artigo complementa nossos conteúdos sobre listas em Python, collections, cópias de objetos, fusos horários e arquivos temporários.

O que é um UUID

UUID significa Universally Unique Identifier. O formato possui 128 bits e costuma ser exibido como 32 dígitos hexadecimais separados por hífens:

550e8400-e29b-41d4-a716-446655440000

O objetivo é permitir geração descentralizada com probabilidade extremamente baixa de colisão. Isso não significa uma garantia matemática absoluta em todas as versões e implementações, mas é suficiente para a maioria dos sistemas.

Gerando um UUIDv4

Para um identificador aleatório geral, a opção mais comum é uuid4().

import uuid

identificador = uuid.uuid4()
print(identificador)
print(type(identificador))
print(identificador.version)

O objeto retornado é uma instância de UUID, não apenas uma string. O Python gera UUIDv4 com aleatoriedade criptograficamente segura, o que reduz colisões e evita a exposição direta de tempo ou endereço de rede.

Converter para string, bytes e inteiro

Uma mesma instância possui várias representações úteis.

import uuid

valor = uuid.uuid4()

print(str(valor))
print(valor.hex)
print(valor.bytes)
print(valor.int)
print(valor.urn)

str() produz o formato padrão com hífens. hex retorna 32 caracteres sem hífens. bytes ocupa 16 bytes. int representa os 128 bits como inteiro. urn produz uma URI como urn:uuid:....

Validando entrada com UUID()

Ao receber um identificador de uma API ou linha de comando, converta-o para UUID antes de usar.

from uuid import UUID


def validar_uuid(texto: str) -> UUID:
    try:
        return UUID(texto)
    except (ValueError, AttributeError, TypeError) as erro:
        raise ValueError("UUID inválido") from erro

O construtor aceita formatos com hífens, sem hífens, com chaves e com prefixo URN. Depois da conversão, você pode comparar objetos de forma consistente e verificar a versão.

UUIDv1 e privacidade

uuid1() combina tempo, sequência de relógio e um identificador de nó. Historicamente, o nó pode ser derivado do endereço MAC da máquina.

import uuid

valor = uuid.uuid1()
print(valor)
print(valor.node)
print(valor.time)

A documentação oficial de uuid alerta que UUIDv1 pode comprometer privacidade ao incluir o endereço de rede. Para novos sistemas, evite v1 quando não houver uma exigência de compatibilidade.

UUIDv3 e UUIDv5: IDs determinísticos

UUIDv3 e UUIDv5 produzem o mesmo identificador para a mesma combinação de namespace e nome. UUIDv3 usa MD5; UUIDv5 usa SHA-1 e normalmente é preferível entre os dois.

import uuid

id_url = uuid.uuid5(
    uuid.NAMESPACE_URL,
    "https://exemplo.com/produtos/42",
)

print(id_url)

Esse comportamento é útil para migrações, importações idempotentes, chaves derivadas de URLs e sincronização entre sistemas. O nome precisa ser canonicalizado: diferenças de maiúsculas, barras finais ou codificação geram UUIDs diferentes.

Namespaces predefinidos

O módulo inclui quatro namespaces conhecidos:

  • NAMESPACE_DNS para nomes de domínio;
  • NAMESPACE_URL para URLs;
  • NAMESPACE_OID para OIDs ISO;
  • NAMESPACE_X500 para nomes X.500.

Você também pode criar um namespace próprio e reutilizá-lo em toda a organização. Trate esse valor como parte do contrato: trocar o namespace muda todos os identificadores derivados.

UUIDv6: tempo reorganizado

UUIDv6 reorganiza os campos temporais do UUIDv1 para melhorar a localidade em índices de banco. Ele foi adicionado ao módulo no Python 3.14.

import uuid

valor = uuid.uuid6()
print(valor)
print(valor.version)

É especialmente útil em sistemas que já dependem da semântica do v1 e precisam de uma ordem binária mais amigável ao banco. Para novos projetos sem legado de v1, o padrão RFC recomenda considerar UUIDv7.

UUIDv7: tempo Unix e ordenação

UUIDv7 incorpora um timestamp Unix em milissegundos nos bits mais significativos e combina o restante com aleatoriedade e mecanismos de monotonicidade.

import datetime as dt
import uuid

valor = uuid.uuid7()
criado_em = dt.datetime.fromtimestamp(
    valor.time / 1000,
    tz=dt.timezone.utc,
)

print(valor)
print(criado_em)

Valores gerados em sequência tendem a ordenar cronologicamente, o que melhora a localidade em índices B-tree em comparação com UUIDv4. Isso não transforma o UUID em um relógio de auditoria confiável; mantenha um campo de data explícito.

Monotonicidade dentro do mesmo milissegundo

Aplicações podem gerar vários UUIDv7 no mesmo milissegundo. A implementação do Python usa um contador para garantir monotonicidade nesse intervalo quando a plataforma não oferece precisão menor.

A ordenação é útil, mas não deve ser confundida com sequência sem lacunas. Processos diferentes, reinicializações e relógios ajustados podem produzir relações que exigem tratamento específico. Use datas e números de sequência separados quando a lógica de negócio exigir ordem total.

UUIDv8: espaço personalizado

UUIDv8 reserva campos para formatos experimentais ou específicos de fornecedor.

import uuid

valor = uuid.uuid8(
    0x12345678,
    0x9ABC,
    0x11223344,
)
print(valor)

Os argumentos possuem limites de bits e valores excedentes são truncados. Por padrão, os componentes não são gerados por um CSPRNG. Portanto, v8 não substitui v4 em contextos que precisam de aleatoriedade segura.

UUID NIL e MAX

O Python 3.14 também oferece valores especiais:

import uuid

print(uuid.NIL)
print(uuid.MAX)

NIL possui todos os bits em zero e pode representar ausência quando um campo exige 128 bits. MAX possui todos os bits em um e pode servir como sentinela superior. Prefira NULL no banco quando ausência real faz parte do modelo, evitando significados ocultos.

Comparação e ordenação

Objetos UUID são comparados pelo atributo inteiro.

valores = [uuid.uuid7() for _ in range(5)]
ordenados = sorted(valores)
assert ordenados == valores

Comparar um UUID com um objeto de outro tipo gera TypeError. Normalize entradas antes de ordenar ou usar como chave.

Armazenamento em banco de dados

As opções comuns são:

  • tipo UUID nativo, quando o banco oferece;
  • 16 bytes binários;
  • texto com 36 caracteres;
  • texto hexadecimal com 32 caracteres.

O tipo nativo normalmente fornece validação e funções adequadas. Binário economiza espaço, mas exige cuidado com ordem de bytes e ferramentas de inspeção. Texto é legível, porém ocupa mais espaço.

UUID como chave primária

UUIDs são úteis quando clientes ou serviços precisam criar registros antes de falar com um banco central. Eles também evitam revelar diretamente a quantidade de registros, diferente de IDs sequenciais.

Por outro lado, UUIDv4 insere valores em posições aleatórias do índice e pode aumentar fragmentação. UUIDv7 melhora a localidade, mas continua maior que um inteiro de 64 bits. Meça impacto conforme volume, banco e padrão de consulta.

UUID não é autorização

Um identificador difícil de adivinhar não substitui controle de acesso. Mesmo um UUIDv4 deve ser tratado apenas como nome do recurso.

# incorreto: liberar apenas porque o UUID existe
# correto: validar usuário, organização, papel e recurso

APIs precisam verificar autenticação e autorização em cada operação. Não use UUID como senha, token de sessão ou segredo criptográfico.

Colisões e restrições únicas

A probabilidade de colisão de UUIDv4 é extremamente baixa, mas o banco ainda deve possuir uma restrição UNIQUE ou chave primária. O gerador reduz a chance; a restrição garante a integridade.

Em caso de conflito, gere outro valor e repita a operação de forma controlada. Nunca remova a restrição apenas porque “UUID não colide”.

IDs determinísticos e idempotência

UUIDv5 é excelente para dados que têm uma chave natural estável.

def id_cliente(sistema: str, codigo: str) -> uuid.UUID:
    nome = f"{sistema.strip().lower()}:{codigo.strip()}"
    return uuid.uuid5(uuid.NAMESPACE_URL, nome)

A canonicalização deve ser documentada e testada. Se uma versão futura mudar a regra, identifique a versão no namespace ou em outro campo para não criar duplicatas silenciosas.

Serialização em JSON

O módulo json não converte UUID automaticamente. Transforme em string na borda.

import json
import uuid

registro = {"id": str(uuid.uuid4()), "nome": "Ana"}
texto = json.dumps(registro)
print(texto)

Ao ler, reconstrua com UUID(). Em frameworks web, serializers e modelos costumam oferecer suporte nativo.

Uso na linha de comando

Desde o Python 3.12, o módulo pode ser executado diretamente. O Python 3.14 adicionou versões 6, 7 e 8 e a opção de gerar vários valores.

python -m uuid
python -m uuid -u uuid7
python -m uuid -C 10
python -m uuid -u uuid5 -n @url -N https://exemplo.com

Esse recurso ajuda em testes, migrações e scripts de implantação sem escrever um programa separado.

RFC 9562 e compatibilidade

O RFC 9562, publicado em 2024, substituiu o RFC 4122. Ele mantém as versões tradicionais e padroniza v6, v7, v8, NIL e MAX.

Sistemas antigos ainda podem exibir a constante RFC_4122 por compatibilidade. O nome permanece, mas o layout atual é especificado pelo RFC mais novo.

Erros frequentes

  • Usar UUIDv1 sem considerar privacidade.
  • Escolher UUIDv4 e esperar ordenação temporal.
  • Usar UUIDv7 como única fonte de data de auditoria.
  • Tratar UUID como token de acesso.
  • Armazenar texto sem validação.
  • Remover a restrição única do banco.
  • Usar UUIDv5 sem canonicalizar o nome.
  • Adotar UUIDv8 sem especificar o formato.

Boas práticas

  • Use v4 para IDs aleatórios gerais.
  • Use v5 para IDs determinísticos por nome.
  • Considere v7 para bancos que se beneficiam de ordenação temporal.
  • Evite v1 em novos projetos por privacidade.
  • Armazene como tipo UUID nativo quando possível.
  • Mantenha restrições de unicidade.
  • Separe identidade de autorização.
  • Teste parsing, versão, round-trip e ordenação.

Conclusão

O módulo uuid no Python oferece uma família de identificadores para necessidades diferentes. UUIDv4 fornece aleatoriedade segura, UUIDv5 cria valores determinísticos, UUIDv6 melhora o layout temporal do legado e UUIDv7 combina timestamp Unix com boa localidade para bancos. UUIDv8 fica reservado a formatos personalizados.

A escolha correta depende do contrato: como o ID é gerado, se precisa ordenar, se deve ser reproduzível e quais informações pode revelar. Com validação, tipo adequado no banco, restrições únicas e autorização independente, UUIDs ajudam sistemas distribuídos a criar identificadores sem coordenação central e sem depender de sequências globais.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Arquivos organizados representando armazenamento temporário seguro no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    tempfile no Python: arquivos temporários

    Aprenda tempfile no Python para criar arquivos e pastas temporárias com segurança, limpeza automática e suporte a Windows e Unix.

    Ler mais

    Tempo de leitura: 8 minutos
    29/07/2026
    Relógios representando fusos horários internacionais com zoneinfo no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    zoneinfo no Python: fusos horários

    Aprenda zoneinfo no Python para converter fusos, lidar com horário de verão, fold, UTC e tzdata sem erros de agendamento.

    Ler mais

    Tempo de leitura: 8 minutos
    29/07/2026
    Ícone de documentos duplicados representando cópia rasa e profunda no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    copy no Python: cópia rasa e profunda

    Aprenda copy no Python para criar cópias rasas, profundas e substituir campos sem compartilhar objetos mutáveis por engano.

    Ler mais

    Tempo de leitura: 8 minutos
    28/07/2026
    Monitor com busca binária e listas ordenadas no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    bisect no Python: listas sempre ordenadas

    Aprenda bisect no Python para manter listas ordenadas, encontrar intervalos e inserir valores com busca binária eficiente.

    Ler mais

    Tempo de leitura: 8 minutos
    27/07/2026
    Desenvolvedor implementando fila de prioridade com heapq no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    heapq no Python: filas de prioridade

    Aprenda heapq no Python para criar filas de prioridade, encontrar menores valores e processar tarefas com heaps eficientes.

    Ler mais

    Tempo de leitura: 7 minutos
    26/07/2026
    Como acelerar código Python usando lru cache
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    Como acelerar seu código Python com @lru_cache em 2 minutos

    Você já sentiu que seu programa está demorando uma eternidade para processar cálculos repetitivos? Sabia que existe uma forma mágica

    Ler mais

    Tempo de leitura: 10 minutos
    06/04/2026