Dicionários em Python – Como criar uma agenda telefônica

No post sobre listas vimos um dos tipos de estruturas para guardar coleções. Neste post vamos falar sobre um outro tipo de coleção que são os dicionários. Além de entender esta estrutura de dados vamos aprender como utilizar as principais funções:

  • chaves e valores
  • adição de itens
  • atualização de itens
  • remoção de itens
  • acesso a itens por meio de chaves
  • como utilizar loops em dicionários

Vamos ver um exemplo de utilização de um dicionário em Python e para isto aprenderemos como criar seu próprio módulo. Por últimos vamos aprender a utilizar um pacote de biblioteca gratuita que é externa ao Python consultando o site PyPi.

O que é um dicionário ou hashmap?

Um dicionário é uma estrutura de dados que pode guardar vários tipos de objetos. A diferença é que os dicionários utilizam chaves (keys) em vez de índices para acessar seu conteúdo. Em Python as chaves podem ser de qualquer tipo, inteiro, string ou até mesmo um objeto. Portanto um dicionário é composto por chave e valor, veja abaixo como declarar um dicionário em Python:

dicionario = {
  "nome": "Marcela",
  "sobrenome": "Freitas",
  "idade": 7
}

Para acessar os valores do dicionário, basta acessar pela chave:

dicionario["nome"] # Marcela
dicionario["idade"] # 7

Também é possível utilizar a função get(key), a diferença é que esta função não retorna erro caso a chave não exista no dicionário, em vez disso, ela retorna None que é o equivalente a null em Pyhton, ou seja, nada, vazio.

dicionario["rua"] # KeyError: 'rua'

dicionario.get("rua") # None

Para atualizar o valor de uma chave, basta setá-lo novamente.

dicionario["idade"] = 8

Iterando nos itens de um dicionário em Python

É possível utilizar o loop for para acessar todos os itens de um dicionário. O padrão do loop for para dicionários é iterar por todas as chaves.

for chave in dicionario:
	print(dicionario[chave])

Também é possível navegar por todos os valores do dicionário diretamente

for valor in dicionario.values():
	print(valor)

E se você quiser navegar por todos os itens e receber a chave e o valor ao mesmo tempo é possível utilizar a função items().

for chave, valor in dicionario.items():
  print(chave, valor)

Para checar se uma chave existe no dicionário é possível utilizar um if.

if "nome" in dicionario:
	print("Nome: " + dicionario["nome"])

A função len() que utilizamos nas listas também pode ser utilizada em dicionários, ela vai retornar a quantidade de itens.  

len(dicionario) #3

Para criar um dicionário vazio, utilize a forma {}. Adicione novos items setando o valor de uma chave e remova com a função pop().

dicionario = {}
dicionario["marca"] = "Mercedez"
dicionario["modelo"] = "Classe A"
dicionario.pop("modelo")

Os dicionários em Python são muito versáteis, é possível guardar dicionários dentro de dicionários. Imagine como funciona sua lista de contatos do telefone, você precisa guardar informações como nome, e-mail, telefone de todos os seus contatos.  Cada contato pode utilizar o nome como chave e como valor um outro dicionário com as propriedades que te interessam.

contatos = {
	"Flávia" : {
    	"nome": "Flávia",
        "telefone": "99234-1234",
        "email": "[email protected]"
        },
    "Daniela Sato": {
    	"nome": "Daniela Sato",
        "telefone": "7658-2091",
        "email": "[email protected]",
        "empresa": "Enterprises"
        }
    }   

Note que o segundo item tem mais propriedades do que o primeiro, esta é uma característica dos dicionários, você pode guardar objetos totalmente diferentes.

Exemplo de uso de dicionário – Lista de contatos

Vamos implementar uma agenda de contatos em Python utilizando esta estrutura de dicionários. Podemos utilizar o mesmo modelo que usamos na calculadora para identificar os comandos que vamos usar. Para esta versão trabalharemos com três comandos: novo(para criar um novo contato), pes(para fazer uma busca por nome) e sair (para sair do programa).

comando = "continue"
contatos = {}

while comando != "sair": 
  comando = input("Digite o comando: (novo, pes, sair):")

Inicializamos um dicionario vazio chamado contatos onde vamos guardar os contatos do usuário. Começaremos implementando o comando “novo”, para isto precisamos receber do usuário o valores para nome, telefone e e-mail. Utilizaremos a função .strip() para remover todos os espaços em branco no começo e no final da string, assim se o usuário digitar “Carla “, o espaço final será removido.

if comando == "novo":
    nome = input("Nome: ").strip()
    telefone = input("Telefone: ").strip()
    email = input("E-mail: ").strip()
    contatos[nome] = {
      "nome": nome,
      "telefone": telefone,
      "email": email
    }

Para implementar o comando “pes” basta procurar o nome digitado pelo usuário no dicionário de contatos. Queremos facilitar a vida do usuário para que ele possa pesquisar o nome independente de maiúsculas e minúsculas. Então devemos transformar o nome procurado em minúsculas utilizando a função lower(). Precisamos garantir que o nome digitado exista no dicionário de contatos e caso contrário imprimir uma mensagem de erro.

if comando == "pes":
	nome = input("Nome: ").lower()
    if nome in contato:
    	contato = contatos[nome]
    	print(contato)
    else:
    	print("Não encontrado")

Como criar um módulo em Python

Neste momento temos uma lista de contatos funcional mas ainda deixa a desejar em alguns aspectos. Podemos melhorar a busca de contatos criando um mecanismo que procure pelo prefixo que o usuário digitou, por exemplo, se buscar “Maria” ele deve nos devolver todas as Marias encontradas.

Portanto queremos fazer uma função para nos ajudar com essa lógica, podemos utilizar a função startswith() que vimos no post Dominando Strings em Python para encontrar todas as chaves que começam com o texto que o usuário digitou. Para organizar melhor nosso código criaremos essa função em um arquivo separado, que vamos chamar de funcoes.py. No repl utilize o botão de novo arquivo.

New File Repl
botão para criar novo arquivo no repl

Por hora o arquivo conterá apenas a função procura_chaves que vai receber um dicionario e um nome que será utilizado como prefixo da busca.

def procura_chaves(dicionario, nome):
  chaves = []
  for chave in dicionario:
    if chave.startswith(nome):
      chaves.append(chave)
  return chaves

A função devolve uma lista de todas as chaves do dicionario que começam com o termo indicado pelo parâmetro nome. Agora podemos alterar o comando “pes” que fizemos para utilizar essa função. Então será necessário importar essa função para o nosso arquivo principal, assim como vimos no post do despertador.

from funcoes import procura_chaves

if comando == "pes":
    nome = input("Nome: ").lower()
    chaves_encontradas = procura_chaves(contatos, nome)

    if len(chaves_encontradas) > 0:
      for chave in chaves_encontradas:
      	print(contatos[chave])

Como importar um pacote em python que imprime uma tabela

O código acima imprime os contatos encontrados com um formato padrão de impressão que o Python utiliza para dicionários, veja o exemplo abaixo:

{'nome': 'Roberta Miranda', 'telefone': '79387498374', 'email': 'roberta
@miranda.com'}{'nome': 'Roberta Silva', 'telefone': '98273498', 'email': 'roberta@silv
a.com'}

Não é uma maneira muito amigável de ver sua lista de contatos, quem sabe não podemos melhorar essa visualização. Para resolver isto vamos utilizar uma biblioteca gratuita que não vem como pate do Python padrão.

Vamos consultar o site PyPi – Python Package Index. Ele tem mais de 200 mil pacotes que podem ser utilizados no seu programa. Esta é a maneira que os programadores compartilham seu trabalho, é normal você se deparar com um problema que já foi resolvido por outra pessoa. Muitos desenvolvedores criam essas bibliotecas e distribuem neste site para ser utilizado por outros desenvolvedores.

Eu encontrei uma biblioteca que faz exatamente o que precisamos: imprime dados em formato de tabela no console, ela se chama tabulate. Para instalar este pacote no repl clique no botão packages:

botão packages do repl
botão packages do repl

Faça a pesquisa pelo nome do pacote:

pesquisa do pacote no repl
pesquisa do pacote no repl

Escolha o pacote tabulate, clique no botão de adicionar e aguarde o repl fazer a instalação.

Continuando, vamos criar uma nova função no nosso modulo de funcoes.py para fazer a impressão dos contatos encontrados. No entanto será necessário transformar os contatos em uma lista, pois é o que a função tabulate utiliza para imprimir.

Nossa função imprime_contatos faz a transformação dos dados dos contatos em uma lista de listas, que é o formato utilizado pela função tabulate.

def imprime_contatos(contatos, chaves):
  table = []
  for chave in chaves:
    table.append([
      contatos[chave]["nome"],
      contatos[chave]["telefone"],
      contatos[chave]["email"]
    ])

  print(tabulate(table, headers=["Nome", "Telefone", "E-mail"], tablefmt="grid"))

Para concluir, vamos chamar a função tabulate passando a lista que criamos e também algumas informações de configuração. A primeira é referente ao cabeçalho (headers) e a segunda é em relação ao formato da tabela que queremos imprimir(grid). Se você quiser saber mais sobre outras opções da função tabulate basta revisar a documentação na pagina do pacote.

print(tabulate(table, headers=["Nome", "Telefone", "E-mail"], tablefmt="grid"))

Com o código acima, a tabela impressa fica muito mais amigável para ler, veja um exemplo:

+-----------------+-------------+---------------------+
| Nome            |    Telefone | E-mail              |
+=================+=============+=====================+
| Roberta Miranda | 79387498374 | [email protected] |
+-----------------+-------------+---------------------+
| Roberta Silva   |    98273498 | [email protected]   |
+-----------------+-------------+---------------------+

Código final: https://repl.it/@julianajuliano/Contatos