Python Conjuntos (set)

A Ana anotou numa lista o número de cada cliente que passou na padaria hoje: [3, 1, 3, 2, 1, 3]. Foram seis visitas, mas quantos clientes diferentes? Para perguntas assim o Python tem o conjunto (em inglês, set): uma coleção que não aceita repetidos. Jogue a lista num conjunto e as repetições somem sozinhas.

Você vai aprender
  • A criar um conjunto com chaves { } ou com set(), e por que os repetidos desaparecem.
  • Que o conjunto não tem ordem: com textos, a ordem do print muda de uma execução para outra.
  • A tirar os repetidos de uma lista e a mostrar o resultado em ordem com sorted().
  • A acrescentar e remover itens: add, remove, discard, clear.
  • A armadilha: {} é um dicionário vazio; conjunto vazio é set().
  • Os erros reais: KeyError, not subscriptable, unhashable type.

A ideia: o álbum de figurinhas

Pense no álbum de figurinhas da Ana. Cada figurinha entra no álbum uma vez só: se ela tirar a figurinha 7 de novo, não tem onde colar, porque o espaço da 7 já está ocupado. E o álbum responde muito bem a uma pergunta: "eu já tenho a 7?". Ele não liga para a ordem em que as figurinhas chegaram; só para quais estão lá.

O conjunto do Python é esse álbum: guarda cada valor uma vez, responde rápido se um valor está nele, e não guarda ordem.

ListaTuplaConjunto
Como se escreve[1, 2, 2](1, 2, 2){1, 2}
Aceita repetidosSimSimNão
Tem ordem e índice ([0])SimSimNão
Pode mudarSimNãoSim (acrescentar e remover)

1. Criando um conjunto

numeros = {3, 1, 2}
print(numeros)
print(type(numeros))
repetidos = {1, 2, 2, 3, 3, 3}
print(repetidos)
print(len(repetidos))
{ … }
Chaves envolvem os itens do conjunto (lista usa colchetes; tupla, parênteses).
3, 1, 2
Os itens, separados por vírgula.
type(numeros)
O tipo se chama set.
{1, 2, 2, 3, 3, 3}
Você escreveu seis valores, mas só três são diferentes. O conjunto guarda cada um uma vez.
$ python3 c_criar.py
{1, 2, 3}
<class 'set'>
{1, 2, 3}
3

Os repetidos sumiram sem aviso nenhum: não é erro escrever um valor duas vezes, o conjunto simplesmente ignora a cópia. E o len conta só os diferentes: 3.


2. O conjunto não tem ordem

Repare que {3, 1, 2} foi mostrado como {1, 2, 3}. Não foi o Python "ordenando" para você: o conjunto guarda os itens do jeito que for mais rápido para achar cada um depois, e isso não tem nada a ver com a ordem em que você escreveu. Com números pequenos costuma parecer ordenado, mas é coincidência:

numeros = {10, 3, 7, 1}
print(numeros)
$ python3 c_ordem.py
{1, 10, 3, 7}

Nem a ordem em que foi escrito, nem a ordem crescente. Com textos é ainda mais curioso: a Ana rodou o mesmo programa três vezes seguidas.

frutas = {"manga", "caju", "acerola", "goiaba"}
print(frutas)
$ python3 c_textos.py
{'manga', 'caju', 'goiaba', 'acerola'}
$ python3 c_textos.py
{'caju', 'goiaba', 'acerola', 'manga'}
$ python3 c_textos.py
{'manga', 'goiaba', 'acerola', 'caju'}

Três ordens diferentes, sem mudar uma letra do programa. Por quê? Para achar um texto rápido, o Python transforma cada texto num número (o hash, uma espécie de "impressão digital" do valor), e por segurança essa conta usa um sorteio novo a cada execução. Mudou o sorteio, mudou a arrumação, mudou a ordem do print. Os números inteiros não passam por esse sorteio, por isso {10, 3, 7, 1} sai sempre igual, mas mesmo assim fora de ordem. (No editor do guia, a ordem dos textos também muda, mas pode se repetir entre um Rodar e outro na mesma página. Não conte com ela em nenhum dos dois.)

Nunca conte com a ordem de um conjunto

Se o seu programa precisa mostrar os itens numa ordem certa, use sorted(conjunto): ele devolve uma lista com os itens em ordem crescente (ou alfabética), sempre igual. Se você precisa da ordem em que os itens chegaram, o conjunto não é a ferramenta certa: use uma lista.


3. Tirando os repetidos de uma lista

O uso mais comum do conjunto no dia a dia: transformar uma lista com repetidos em um conjunto com set(lista). Voltando às visitas da padaria:

visitas = [3, 1, 3, 2, 1, 3]
unicos = set(visitas)
print(unicos)
print(len(visitas), "visitas,", len(unicos), "clientes diferentes")
$ python3 c_lista.py
{1, 2, 3}
6 visitas, 3 clientes diferentes

Com textos, junte o set() ao sorted() para ter um resultado arrumado. E o in pergunta se um valor está no conjunto:

cidades = ["Teresina", "Parnaíba", "Teresina", "Picos", "Parnaíba"]
diferentes = set(cidades)
print(len(diferentes))
print(sorted(diferentes))
print("Picos" in diferentes)
print("Floriano" in diferentes)
$ python3 c_sorted.py
3
['Parnaíba', 'Picos', 'Teresina']
True
False
set(cidades)
Cria um conjunto com os itens da lista: as repetições somem. A lista cidades continua igual.
len(diferentes)
Quantas cidades diferentes: 3.
sorted(diferentes)
Uma lista com os itens do conjunto em ordem alfabética. Essa linha sai igual em toda execução.
"Picos" in diferentes
Pergunta se o valor está no conjunto. É a especialidade dele: mesmo com milhões de itens, responde na hora.

Um texto também pode virar conjunto: set("banana") é o conjunto das letras diferentes da palavra.

print(sorted(set("banana")))
print(len(set("banana")))
$ python3 c_letras.py
['a', 'b', 'n']
3

Missão: a lista de convidados do aniversário tem nomes repetidos (gente que confirmou duas vezes). Use set() para contar quantas pessoas diferentes vêm. A resposta certa é 4.

lista = ["Ana", "Bia", "Ana", "Caio", "Davi", "Bia"]
print("Convidados:", len(lista))
lista = ["Ana", "Bia", "Ana", "Caio", "Davi", "Bia"]
pessoas = set(lista)
print("Convidados:", len(pessoas))

4. Acrescentando e removendo itens

O conjunto pode mudar: dá para pôr e tirar itens. Como ele não tem ordem, não existe "pôr no fim" (append) nem "pôr na posição 2" (insert); existe só pôr: add.

vistos = {1, 2}
vistos.add(3)
vistos.add(2)
print(vistos)
vistos.remove(1)
print(vistos)
vistos.discard(10)
print(vistos)
vistos.clear()
print(vistos)
$ python3 c_add.py
{1, 2, 3}
{2, 3}
{2, 3}
set()
vistos.add(3)
"Adicionar": põe o 3 no conjunto.
vistos.add(2)
O 2 já estava lá: não acontece nada, e não é erro.
vistos.remove(1)
"Remover": tira o 1. Se o item não estiver no conjunto, dá KeyError (veja Quando dá errado).
vistos.discard(10)
"Descartar": tira o item se ele estiver lá; se não estiver, fica quieto. O 10 não estava, e nada aconteceu.
vistos.clear()
"Limpar": esvazia o conjunto.
set()
É assim que o Python mostra um conjunto vazio. Não é {}; a próxima seção explica por quê.

Existe também o pop(), que tira e devolve um item qualquer. "Qualquer" mesmo: como não há ordem, você não escolhe qual. Use quando tanto faz qual item sai.

Percorrendo com for

Dá para passar por um conjunto com for, mas a ordem é a do conjunto (ou seja, nenhuma que você controle). Para uma ordem certa, percorra o sorted():

notas = {7, 9, 7, 10}
for nota in sorted(notas):
    print(nota)
$ python3 c_for.py
7
9
10

5. {} é dicionário, não conjunto

Esta pega muita gente. As chaves { } são usadas por dois tipos do Python: o conjunto e o dicionário. Com itens dentro, o Python sabe qual é qual. Mas {} vazio, sem nada, é um dicionário, porque o dicionário chegou primeiro na linguagem. Para um conjunto vazio, use set().

a = {}
b = set()
print(type(a))
print(type(b))
print(b)
$ python3 c_vazio.py
<class 'dict'>
<class 'set'>
set()
EscritaTipo
{1, 2, 3}Conjunto (set)
{"pão": 0.5} (com dois-pontos)Dicionário (dict)
{}Dicionário vazio
set()Conjunto vazio

Missão: o programa quer guardar os nomes de quem já foi atendido, sem repetir, mas dá AttributeError: 'dict' object has no attribute 'add'. Conserte a primeira linha.

vistos = {}
for nome in ["Caio", "Bia", "Caio"]:
    vistos.add(nome)
print(sorted(vistos))
vistos = set()
for nome in ["Caio", "Bia", "Caio"]:
    vistos.add(nome)
print(sorted(vistos))

6. O que pode entrar num conjunto

Só valores que não mudam podem entrar num conjunto: números, textos, True/False, tuplas. Uma lista não pode, porque ela pode mudar depois de entrar, e o conjunto perderia a "impressão digital" dela. Uma tupla pode:

pontos = {(1, 2), (3, 4), (1, 2)}
print(len(pontos))
print((1, 2) in pontos)
$ python3 c_tupla_dentro.py
2
True

A tupla (1, 2) repetida contou uma vez só. Com listas, o resultado está em Quando dá errado.

E um conjunto que não muda?

Existe: o frozenset ("conjunto congelado"). É para o conjunto o que a tupla é para a lista: frozenset({1, 2, 3}) funciona como um conjunto, mas não tem add nem remove. É raro no começo; basta saber que existe.


Formas diferentes de criar um conjunto

FormaResultadoQuando usar
{1, 2, 3}{1, 2, 3}Quando você já sabe os itens
set([1, 2, 2, 3]){1, 2, 3}Para tirar os repetidos de uma lista (ou tupla)
set("banana")as letras a, b, nPara as letras diferentes de um texto
set()set()Conjunto vazio, para encher com add. Nunca {}

Lista, tupla ou conjunto?

SituaçãoUse
A ordem importa, ou os repetidos importam (cada visita conta)Lista
Valores fixos, que andam juntosTupla
Só importa quais valores existem, sem repetirConjunto
Você vai perguntar muitas vezes "isto está aqui?"Conjunto

Conjuntos também sabem fazer contas de conjunto, como na escola: juntar dois, ver o que eles têm em comum, o que um tem e o outro não. É a próxima aula: União, Interseção e Diferença.


Quando dá errado

Pedir um item pelo índice
numeros = {3, 1, 2}
print(numeros[0])
$ python3 c_indice.py
Traceback (most recent call last):
  File "/home/ana/c_indice.py", line 2, in <module>
    print(numeros[0])
          ~~~~~~~^^^
TypeError: 'set' object is not subscriptable
line 2
O erro está na linha 2, no numeros[0] (o pedaço marcado com ~~~^^^).
TypeError
"Erro de tipo": essa operação não existe para esse tipo.
'set' object is not subscriptable
"Um objeto set não aceita índice" (os colchetes depois do nome). Sem ordem, não existe "o item 0".

Como consertar: se você precisa de posições, converta: sorted(numeros)[0] dá o menor item. Para saber se um item está lá, use in.

Remover um item que não está lá
vistos = {1, 2, 3}
vistos.remove(10)
$ python3 c_remove_erro.py
Traceback (most recent call last):
  File "/home/ana/c_remove_erro.py", line 2, in <module>
    vistos.remove(10)
    ~~~~~~~~~~~~~^^^^
KeyError: 10

KeyError: 10: "erro de chave: 10". O 10 não está no conjunto, e o remove avisa com um erro. Como consertar: use discard(10), que não reclama, ou pergunte antes: if 10 in vistos: vistos.remove(10).

{} no lugar de set()
convidados = {}
convidados.add("Ana")
$ python3 c_vazio_erro.py
Traceback (most recent call last):
  File "/home/ana/c_vazio_erro.py", line 2, in <module>
    convidados.add("Ana")
    ^^^^^^^^^^^^^^
AttributeError: 'dict' object has no attribute 'add'

A mensagem fala de 'dict', e não de set: é a pista. {} criou um dicionário, e dicionário não tem add. Como consertar: convidados = set().

Lista dentro de um conjunto
pares = {[1, 2], [3, 4]}
$ python3 c_lista_dentro.py
Traceback (most recent call last):
  File "/home/ana/c_lista_dentro.py", line 1, in <module>
    pares = {[1, 2], [3, 4]}
            ^^^^^^^^^^^^^^^^
TypeError: cannot use 'list' as a set element (unhashable type: 'list')

"Não é possível usar list como item de um conjunto (tipo sem hash: list)". Unhashable quer dizer "não dá para tirar a impressão digital": como a lista pode mudar, ela não pode entrar no conjunto. Como consertar: use tuplas: {(1, 2), (3, 4)}.

Em versões mais antigas do Python 3.14

A primeira parte da mensagem (cannot use 'list' as a set element) é novidade do Python 3.14. No Python 3.13 (o do Debian 13) aparece só TypeError: unhashable type: 'list'.


Referência rápida

EscritaO que faz
s = {1, 2, 3}Cria um conjunto
s = set()Conjunto vazio ({} é dicionário)
set(lista)Conjunto com os itens da lista, sem repetidos
len(s)Quantos itens diferentes
x in sTrue se x está no conjunto
s.add(x)Põe x (se já estava, nada muda)
s.remove(x)Tira x; KeyError se não estiver
s.discard(x)Tira x se estiver; senão, nada
s.pop()Tira e devolve um item qualquer
s.clear()Esvazia
sorted(s)Lista com os itens em ordem (o jeito de mostrar sempre igual)
SintomaCausa provável
TypeError: 'set' object is not subscriptableUsou índice (s[0]): conjunto não tem posição
KeyError: 10remove de um item que não está lá
AttributeError: 'dict' object has no attribute 'add'Criou com {}, que é dicionário
TypeError: cannot use 'list' as a set element (unhashable type: 'list')Lista dentro do conjunto: use tupla
A ordem do print muda a cada execuçãoNormal: conjunto não tem ordem. Use sorted()

Exercícios

1. Conjunto vazio

Complete para criar um conjunto vazio:

pessoas =

2. Quantos diferentes?

Quanto vale len({5, 5, 6, 5, 7})?

3. Sem reclamar

Complete o método que tira o 4 do conjunto sem dar erro se ele não estiver lá:

numeros.(4)

4. O que type({}) mostra?

5. A Ana rodou duas vezes print({"pão", "leite", "café"}) e a ordem saiu diferente. O que aconteceu?

6. Qual destes valores não pode ser item de um conjunto?

Missão final: as cidades dos clientes

Missão: a lista tem a cidade de cada cliente, com repetições. Mostre quantas cidades diferentes são (Cidades diferentes: 3) e, na linha seguinte, a lista delas em ordem alfabética, que sai igual em toda execução.

clientes = ["Teresina", "Picos", "Teresina", "Parnaíba", "Picos", "Teresina"]
print(clientes)
clientes = ["Teresina", "Picos", "Teresina", "Parnaíba", "Picos", "Teresina"]
cidades = set(clientes)
print("Cidades diferentes:", len(cidades))
print(sorted(cidades))

Resumo

  • O conjunto (set) guarda valores sem repetir: {1, 2, 2} vira {1, 2}.
  • Ele não tem ordem nem índice. Com textos, a ordem do print muda de uma execução para outra; para mostrar em ordem, use sorted().
  • set(lista) tira os repetidos de uma lista; len conta os diferentes; in pergunta se um valor está lá.
  • add põe; remove tira (com KeyError se não houver); discard tira sem reclamar; clear esvazia.
  • {} é dicionário vazio; conjunto vazio é set().
  • Só valores que não mudam entram num conjunto: tupla sim, lista não (unhashable type: 'list').