A classe dict do Python oferece muitos métodos úteis para trabalhar com dicionários.
Alguns foram apresentados no conceito de dicts.
Aqui vamos ver mais alguns, além de algumas técnicas para iterar sobre dicionários e manipulá-los.
setdefault() para inserir sem errosO conceito de dicionário já mostrou que .get(key, <default value>) retorna um value existente ou o default value quando uma key não é encontrada em um dicionário, evitando assim um KeyError.
Isso funciona bem em situações nas quais você prefere não ter tratamento de erro extra, mas não pode confiar que a key procurada estará presente.
Para uma operação de inserção igualmente "segura" (sem KeyError), existe o método .setdefault(key, <default value>).
O setdefault(key, <default value>) retorna o value se a key for encontrada no dicionário.
Se a chave não for encontrada, ele insere o par (key, default value) e retorna o default value para uso.
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
# Looking for the value associated with key "Rock Brown".
# The key does not exist, so it is added with the default value, and the value is returned.
>>> palette_I.setdefault('Rock Brown', '#694605')
'#694605'
# The (key, default value) pair has now been added to the dictionary.
>>> palette_I
{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Rock Brown': '#694605'}
fromkeys() para popular um dicionário a partir de um iterávelPara popular rapidamente um dicionário com várias keys e valores padrão, o método de classe fromkeys(iterable, <default value>) itera sobre um iterável de keys e cria um novo dict.
Todos os values serão definidos com o default value fornecido:
>>> new_dict = dict.fromkeys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'], 'fill in hex color here')
{'Grassy Green': 'fill in hex color here',
'Purple Mountains Majesty': 'fill in hex color here',
'Misty Mountain Pink': 'fill in hex color here'}
Os métodos .keys(), .values() e .items() retornam views iteráveis de um dicionário.
Essas views podem ser usadas para percorrer as entradas com facilidade, sem alterá-las.
As views também são dinâmicas: quando os dados subjacentes do dicionário mudam, o view object associado reflete a mudança:
>>> palette_I = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd'}
# Using .keys() returns a list of keys.
>>> palette_I.keys()
dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'])
# Using .values() returns a list of values.
>>> palette_I.values()
dict_values(['#9bc400', '#8076a3', '#f9c5bd'])
# Using .items() returns a list of (key, value) tuples.
>>> palette_I.items()
dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', '#8076a3'), ('Misty Mountain Pink', '#f9c5bd')])
# Views are dynamic. Changing values in the dict changes all of the associated views.
>>> palette_I['Purple Mountains Majesty'] = (128, 118, 163)
>>> palette_I['Deep Red'] = '#932432'
>>> palette_I.values()
dict_values(['#9bc400', (128, 118, 163), '#f9c5bd', '#932432'])
>>> palette_I.keys()
dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink', 'Deep Red'])
>>> palette_I.items()
dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', (128, 118, 163)), ('Misty Mountain Pink', '#f9c5bd'), ('Deep Red', '#932432')])
.keys(), .values() e .items()
No Python 3.7+, os dicts preservam a ordem em que as entradas são inseridas, permitindo uma iteração primeiro a entrar, primeiro a sair (FIFO) ao usar .keys(), .values() ou .items().
No Python 3.8+, as views também são reversíveis.
Isso permite iterar sobre chaves, valores ou pares (key, value) na ordem último a entrar, primeiro a sair (LIFO) usando reversed(<dict>.keys()), reversed(<dict>.values()) ou reversed(<dict>.items()):
>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
# Iterating in insertion order (First in, first out)
>>> for item in palette_II.items():
... print(item)
...
('Factory Stone Purple', '#7c677f')
('Green Treeline', '#478559')
('Purple baseline', '#161748')
# Iterating in the reverse direction. (Last in, first out)
>>> for item in reversed(palette_II.items()):
... print (item)
...
('Purple baseline', '#161748')
('Green Treeline', '#478559')
('Factory Stone Purple', '#7c677f')
Dicionários não têm um método de ordenação embutido.
No entanto, é possível ordenar uma view de dict usando a função embutida sorted() com dict.items().
A view ordenada pode então ser usada para criar um novo dicionário.
Assim como na iteração, a ordenação padrão é feita sobre as keys do dicionário.
# Default ordering for a dictionary is insertion order (First in, first out).
>>> color_palette = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
# The default sort order for a dictionary uses the keys.
>>> sorted_palette = dict(sorted(color_palette.items()))
>>> sorted_palette
{'Factory Stone Purple': '#7c677f',
'Grassy Green': '#9bc400',
'Green Treeline': '#478559',
'Misty Mountain Pink': '#f9c5bd',
'Purple Mountains Majesty': '#8076a3',
'Purple baseline': '#161748'}
.update()
<dict_one>.update(<dict_two>) pode ser usado para combinar dois dicionários.
Esse método pega os pares (key,value) de <dict_two> e os escreve em <dict_one>:
>>> palette_I = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd'}
>>> palette_II = {'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple Baseline': '#161748'}
>>> palette_I.update(palette_II)
# Note that new items from palette_II are added.
>>> palette_I
{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple Baseline': '#161748'}
Onde as chaves dos dois dicionários se sobrepõem, o value em dict_one será sobrescrito pelo value correspondente de dict_two:
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
>>> palette_III = {'Grassy Green': (155, 196, 0), 'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189)}
>>> palette_I.update(palette_III)
# Overlapping values in palette_I are replaced with values from palette_III
>>> palette_I
{'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189),
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559', 'Purple baseline': '#161748'}
| e |=)O Python 3.9 introduz uma forma diferente de combinar dicts: os operadores de union.
dict_one | dict_two cria um novo dicionário, formado pelos pares (key, value) de dict_one e dict_two.
Quando os dois dicionários compartilham chaves, os valores de dict_two têm precedência.
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
>>> new_dict = palette_I | palette_II
>>> new_dict
...
{'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
dict_one |= other se comporta de forma semelhante a <dict_one>.update(<other>), mas, nesse caso, other pode ser tanto um dict quanto um iterável de pares (key, value):
>>> palette_III = {'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189)}
>>> new_dict |= palette_III
>>> new_dict
...
{'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189),
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
Para uma explicação detalhada sobre dicionários e métodos para trabalhar com eles, o tutorial oficial e a referência oficial da biblioteca são ótimos pontos de partida.
O Real Python e o Finxter também têm artigos bem completos sobre dicionários em Python.
A Mecha Munch™, uma empresa de automação de compras de supermercado, acabou de contratar você para trabalhar no app de pedidos deles. Sua equipe tem a tarefa de construir um MVP (produto mínimo viável) que gerencia todas as atividades básicas do carrinho de compras, permitindo que os usuários adicionem, removam e ordenem seus pedidos de supermercado. Felizmente, outra equipe cuida de todas as funções de dinheiro e finalização da compra!
O MVP deve permitir que o usuário adicione itens ao carrinho de compras. Pode ser um único item ou vários itens de uma vez. Como este é um MVP, a quantidade de itens é indicada por repetições. Se um usuário quiser adicionar 2 Oranges, 'Oranges' vai aparecer duas vezes no iterável de entrada. Se o usuário já tiver o item no carrinho, a quantidade no carrinho deve ser aumentada em 1. Se o item for novo no carrinho, ele deve ser adicionado com quantidade 1.
Crie a função add_item(<current_cart>, <items_to_add>) que recebe um dicionário de carrinho e qualquer iterável semelhante a uma lista de itens a adicionar como argumentos.
Ela deve retornar um dicionário de carrinho de compras novo/atualizado para o usuário.
>>> add_item({'Banana': 3, 'Apple': 2, 'Orange': 1},
('Apple', 'Apple', 'Orange', 'Apple', 'Banana'))
{'Banana': 4, 'Apple': 5, 'Orange': 2}
>>> add_item({'Banana': 3, 'Apple': 2, 'Orange': 1},
['Banana', 'Orange', 'Blueberries', 'Banana'])
{'Banana': 5, 'Apple': 2, 'Orange': 2, 'Blueberries': 1}
Ih, ih. Parece que a equipe de produto está fazendo aumento descontrolado de funcionalidades. Eles querem adicionar funcionalidades extras ao MVP. A aplicação agora precisa criar um carrinho de compras lendo os itens do app de notas de um usuário. Conveniente para os usuários, mas um pouco mais de trabalho para a equipe.
Crie a função read_notes(<notes>) que pode receber qualquer iterável semelhante a uma lista como argumento.
A função deve interpretar os itens e criar um carrinho/dicionário de compras do usuário.
Cada item deve ser adicionado com quantidade 1.
O novo carrinho do usuário deve então ser retornado.
>>> read_notes(('Banana','Apple', 'Orange'))
{'Banana': 1, 'Apple': 1, 'Orange': 1}
>>> read_notes(['Blueberries', 'Pear', 'Orange', 'Banana', 'Apple'])
{'Blueberries' : 1, 'Pear' : 1, 'Orange' : 1, 'Banana' : 1, 'Apple' : 1}
O app tem uma seção de "ideias" que fica cheia de receitas prontas de diversas culinárias. O usuário pode selecionar qualquer uma dessas receitas e ter todos os seus ingredientes adicionados automaticamente ao carrinho de compras. A gerente de projeto pediu que você criasse uma forma de editar essas receitas de "ideias", já que a equipe de conteúdo fica mudando ingredientes e quantidades.
Crie a função update_recipes(<ideas>, <recipe_updates>) que recebe um dicionário de "ideias" e um iterável de atualizações de receitas como argumentos.
A função deve retornar o dicionário de "ideias" novo/atualizado.
>>>update_recipes(
{'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}},
(('Banana Bread', {'Banana': 4, 'Walnuts': 2, 'Flour': 1, 'Butter': 1, 'Milk': 2, 'Eggs': 3}),)
)
...
{'Banana Bread': {'Banana': 4, 'Walnuts': 2, 'Flour': 1, 'Butter': 1, 'Milk': 2, 'Eggs': 3},
'Raspberry Pie': {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}}
>>> update_recipes(
{'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1},
'Pasta Primavera': {'Eggs': 1, 'Carrots': 1, 'Spinach': 2, 'Tomatoes': 3, 'Parmesan': 2, 'Milk': 1, 'Onion': 1}},
[('Raspberry Pie', {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2}),
('Pasta Primavera', {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1}),
('Blueberry Crumble', {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3})]
)
...
{'Banana Bread': {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie': {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2},
'Pasta Primavera': {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1},
'Blueberry Crumble': {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3}}
Depois que o usuário começa um carrinho, o app permite ordenar os itens em ordem alfabética. Isso facilita encontrar as coisas e ajuda quando há erros de digitação, como ter 'potatoes' e 'Potato' no banco de dados.
Crie a função sort_entries(<cart>) que recebe um carrinho/dicionário de compras como argumento e retorna um novo, ordenado alfabeticamente.
>>> sort_entries({'Banana': 3, 'Apple': 2, 'Orange': 1})
{'Apple': 2, 'Banana':3, 'Orange': 1}
O app precisa enviar o carrinho de um determinado usuário para a loja para separação. No entanto, os atendentes da loja precisam saber em qual corredor o item pode ser encontrado e se ele precisa de refrigeração. Então (de forma bem arbitrária) o "carrinho de separação" precisa ser ordenado em ordem alfabética inversa, com as quantidades dos itens combinadas com as informações de localização e refrigeração.
Crie a função send_to_store(<cart>, <aisle_mapping>) que recebe um carrinho de compras do usuário e um dicionário que tem o número do corredor da loja e um True/False para a refrigeração necessária para cada item.
A função deve return um "carrinho de separação" combinado que tem (quantidade, corredor e refrigeração) para cada item que o cliente está pedindo.
Os itens devem aparecer em ordem alfabética inversa.
>>> send_to_store({'Banana': 3, 'Apple': 2, 'Orange': 1, 'Milk': 2},
{'Banana': ['Aisle 5', False], 'Apple': ['Aisle 4', False], 'Orange': ['Aisle 4', False], 'Milk': ['Aisle 2', True]})
{'Orange': [1, 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True], 'Banana': [3, 'Aisle 5', False], 'Apple': [2, 'Aisle 4', False]}
O app não pode simplesmente fazer pedidos de clientes sem parar. Uma hora a loja vai ficar sem diversos produtos. Por isso, o MVP do seu app precisa atualizar o inventário da loja toda vez que um usuário envia seu pedido para a loja. Caso contrário, os clientes vão pedir produtos que na verdade não estão disponíveis.
Crie a função update_store_inventory(<fulfillment_cart>, <store_inventory>) que recebe um "carrinho de separação" e um inventário da loja.
A função deve reduzir as quantidades do inventário da loja pelo número "pedido" no "carrinho de separação" e então retornar o inventário atualizado da loja.
Onde a contagem de um item da loja cair para 0, a contagem deve ser substituída pela mensagem 'Out of Stock'.
>>> update_store_inventory({'Orange': [1, 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True], 'Banana': [3, 'Aisle 5', False], 'Apple': [2, 'Aisle 4', False]},
{'Banana': [15, 'Aisle 5', False], 'Apple': [12, 'Aisle 4', False], 'Orange': [1, 'Aisle 4', False], 'Milk': [4, 'Aisle 2', True]})
{'Banana': [12, 'Aisle 5', False], 'Apple': [10, 'Aisle 4', False], 'Orange': ['Out of Stock', 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True]}
Crie sua conta no Exercism para aprender e dominar Python com 17 conceitos146 exercícios e mentoria humana de verdade, tudo de graça.