Após a explicação de hashables e hash table, podemos prosseguir com a teoria de conjuntos e dicionários.
Conjuntos em Python são relativamente novos na linguagem, sendo introduzidos como tipos embutidos a partir da versão 2.6 (a atual é a 3.7). Um conjunto é uma coleção de objetos únicos e é definido por meio de chaves ou por meio da chamada ao seu construtor "set":
In [1]: conjunto_1 = {1} # Preciso adicionar um elemento no mínimo já na construção do conjunto pois não se pode iniciar um conjunto dessa forma sem introduzir um objeto.
In [2]: conjunto_2 = set() # Criando desta forma eu não preciso introduzir nenhum elemento na construção do conjunto.
In [3]: conjunto_3 = set([1, 2, 3]) # Ao criar usando o construtor "set", preciso introduzir um iterável caso já queira iniciar o conjunto com valores.
Confirmando que foram criados conjuntos:
In [6]: type(conjunto_1)
Out[6]: set
In [7]: type(conjunto_2)
Out[7]: set
In [8]: type(conjunto_3)
Out[8]: set
Caso eu crie um conjunto usando a forma literal, com chaves, mas sem nada dentro:
In [9]: conjunto_falso = {}
In [10]: type(conjunto_falso)
Out[10]: dict
Criei um dicionário em vez de um conjunto dessa forma.
Sets obedecem à teoria de conjuntos da matemática, sendo assim, não existem conjuntos com elementos repetidos. Devido a essa característica, uma das funções de conjuntos é retirar elementos repetidos de iteráveis:
In [11]: minha_lista = [1, 1, 1, 2, 2, 2, 3, 4, 5, 6, 6, 6, 7, 8, 9, 9, 9]
In [12]: set(minha_lista)
Out[12]: {1, 2, 3, 4, 5, 6, 7, 8, 9}
Esse é um dos motivos pelo qual qualquer elemento dentro de um conjunto deve ser hashable (relembrem do tópico passado de hashables e hash table -
2.5 - Python - Hashables, hash table e introdução a dicionários - Tecnologia - Bastter.comDessa forma, inserir listas dentro de conjuntos irá ocasionar erros:
In [13]: l1 = [1, 2, 3]
In [14]: l2 = [4, 5, 6]
In [15]: conj = {l1, l2}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-57dee220ce48> in <module>
----> 1 conj = {l1, l2}
TypeError: unhashable type: 'list'
Devido à característica de obedecer à teoria dos conjuntos, podemos elaborar operações de conjuntos como união, interseção, diferença entre conjuntos, etc, de forma bastante simples e intuitiva, que de forma contrária à sintaxe usada aqui o código teria muitas linhas, com laços e lógica condicional desnecessária.
In [1]: a = {1, 2, 3, 4}
In [2]: b = {2, 4, 5, 7}
In [3]: a | b # Devolve a U b, ou a união b
Out[3]: {1, 2, 3, 4, 5, 7}
In [4]: a & b # Devolve a interseção b, mas aqui o site imprimiu na tela também "amp;", ignorem essa parte
Out[4]: {2, 4}
In [5]: a - b # Devolve a diferença de a - b
Out[5]: {1, 3}
In [6]: b - a # Devolve a diferença entre b - a
Out[6]: {5, 7}
In [7]: 1 in a # Pergunta se a contém 1
Out[7]: True
Conjuntos também possuem alguns métodos adicionais:
In [1]: a = {x for x in range(5)} # Também é possível fazer set comprehensions assim como com as listas
In [2]: a
Out[2]: {0, 1, 2, 3, 4}
In [3]: a.add(5) # Adiciona o 5 em a
In [4]: a
Out[4]: {0, 1, 2, 3, 4, 5}
In [5]: a.pop() # Retira e retorna o primeiro elemento, diferente do pop() em listas que retira e retorna o último elemento
Out[5]: 0
In [6]: b = a.copy() # Cria uma cópia de a em b
In [7]: b
Out[7]: {1, 2, 3, 4, 5}
In [8]: b.remove(3) # Remove o objeto passado como parâmetro
In [9]: b
Out[9]: {1, 2, 4, 5}
In [13]: a.clear() # Apaga todos os elementos do conjunto
In [14]: a
Out[14]: set()
Conjuntos não retornam seus elementos caso sejam buscados por índice, pois a ordem não interessa em conjuntos:
In [20]: b
Out[20]: {1, 2, 4, 5}
In [21]: b[2] # Tentativa de obter o elemento da segunda posição
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-21-9fa989ab7a1d> in <module>
----> 1 b[2] # Tentativa de obter o elemento da segunda posição
TypeError: 'set' object is not subscriptable
Também posso criar conjuntos imutáveis, ou frozensets, usando o construtor frozenset:
In [28]: b
Out[28]: {1, 2, 4, 5}
In [29]: b_congelado = frozenset(b)
In [30]: b == b_congelado
Out[30]: True
In [31]: b is b_congelado
Out[31]: False
In [32]: b_congelado.add(3)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-32-edf5592397f7> in <module>
----> 1 b_congelado.add(3)
AttributeError: 'frozenset' object has no attribute 'add'
In [33]: type(b_congelado)
Out[33]: frozenset