39. Módulos Essenciais da Biblioteca Padrão
A biblioteca padrão (standard library) do Python é uma coleção de módulos que já vêm embutidos no Python — você não precisa instalar nada extra para usá-los. Esses módulos fornecem ferramentas poderosas para tarefas comuns de programação: gerar números aleatórios, trabalhar com datas e horários, trocar dados com outros programas e usar estruturas de dados especializadas que vão além de listas e dicionários básicos.
Neste capítulo, vamos explorar cinco módulos essenciais da biblioteca padrão que você vai usar com frequência na programação Python do mundo real.
39.1) Gerando Aleatoriedade com random
O módulo random fornece funções para gerar números aleatórios e fazer seleções aleatórias. Isso é útil para simulações, jogos, testes, amostragem de dados e qualquer situação em que você precise de comportamento imprevisível.
39.1.1) Gerando Inteiros Aleatórios com randint()
A função randint() gera um inteiro aleatório entre dois valores, incluindo as duas extremidades:
import random
# Simular a rolagem de um dado de seis lados
die_roll = random.randint(1, 6)
print(f"You rolled: {die_roll}") # Output: You rolled: 4 (varies each run)
# Gerar uma idade aleatória entre 18 e 65
age = random.randint(18, 65)
print(f"Random age: {age}") # Output: Random age: 42 (varies)Observe que tanto o valor inicial quanto o valor final são incluídos nos resultados possíveis. randint(1, 6) pode retornar 1, 2, 3, 4, 5 ou 6 — todos os seis valores são possíveis.
Aqui vai um exemplo prático que simula várias rolagens de dados:
import random
# Simular a rolagem de dois dados e calcular a soma deles
die1 = random.randint(1, 6)
die2 = random.randint(1, 6)
total = die1 + die2
print(f"Die 1: {die1}") # Output: Die 1: 3 (varies)
print(f"Die 2: {die2}") # Output: Die 2: 5 (varies)
print(f"Total: {total}") # Output: Total: 8 (varies)
if total == 7:
print("Lucky seven!")
elif total == 2 or total == 12:
print("Snake eyes or boxcars!")Por que as duas extremidades são incluídas: Isso torna randint() intuitiva para casos de uso comuns. Quando você quer um número de 1 a 6 (como um dado), você escreve randint(1, 6) e tanto 1 quanto 6 são resultados possíveis.
39.1.2) Gerando Números de Ponto Flutuante Aleatórios
Para números decimais aleatórios, use random() (retorna um float entre 0.0 e 1.0) ou uniform() (retorna um float entre dois valores especificados):
import random
# Gerar um float aleatório entre 0.0 e 1.0 (0.0 incluído, 1.0 excluído)
probability = random.random()
print(f"Random probability: {probability:.4f}") # Output: Random probability: 0.7284 (varies)
# Gerar uma temperatura aleatória entre 15.0 e 30.0 graus
temperature = random.uniform(15.0, 30.0)
print(f"Temperature: {temperature:.2f}°C") # Output: Temperature: 23.47°C (varies)
# Gerar um preço aleatório entre $10.00 e $99.99
price = random.uniform(10.0, 99.99)
print(f"Price: ${price:.2f}") # Output: Price: $45.67 (varies)A função random() é útil quando você precisa de um valor de probabilidade ou uma porcentagem. A função uniform() é melhor quando você precisa de um decimal aleatório dentro de um intervalo específico.
39.1.3) Fazendo Escolhas Aleatórias com choice()
A função choice() seleciona aleatoriamente um elemento de uma sequência (lista, tupla ou string):
import random
# Selecionar aleatoriamente uma cor
colors = ["red", "blue", "green", "yellow", "purple"]
selected_color = random.choice(colors)
print(f"Selected color: {selected_color}") # Output: Selected color: green (varies)
# Selecionar aleatoriamente um vencedor entre participantes
participants = ["Alice", "Bob", "Charlie", "Diana"]
winner = random.choice(participants)
print(f"The winner is: {winner}") # Output: The winner is: Bob (varies)
# Selecionar aleatoriamente um caractere de uma string
vowels = "aeiou"
random_vowel = random.choice(vowels)
print(f"Random vowel: {random_vowel}") # Output: Random vowel: i (varies)Isso é particularmente útil para jogos, amostragem aleatória ou seleção de dados de teste aleatórios. Cada elemento da sequência tem a mesma probabilidade de ser escolhido.
Aqui vai um exemplo mais complexo que simula um jogo simples de quiz:
import random
# Perguntas do quiz com suas respostas
questions = [
("What is 2 + 2?", "4"),
("What is the capital of France?", "Paris"),
("What color is the sky?", "blue")
]
# Selecionar aleatoriamente uma pergunta
question, correct_answer = random.choice(questions)
print(f"Question: {question}")
user_answer = input("Your answer: ")
if user_answer.lower() == correct_answer.lower():
print("Correct!")
else:
print(f"Wrong! The answer was: {correct_answer}")39.1.4) Selecionando Vários Itens Aleatórios com sample()
Quando você precisa selecionar vários itens únicos de uma sequência, use sample(). Isso é como tirar cartas de um baralho sem reposição — depois que um item é selecionado, ele não será selecionado novamente:
import random
# Selecionar 3 alunos aleatórios para um trabalho em grupo
students = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"]
group = random.sample(students, 3)
print(f"Group members: {group}") # Output: Group members: ['Diana', 'Alice', 'Frank'] (varies)
# Sortear 5 números de loteria de 1 a 50 (sem duplicatas)
lottery_numbers = random.sample(range(1, 51), 5)
lottery_numbers.sort() # Ordenar para exibição
print(f"Lottery numbers: {lottery_numbers}") # Output: Lottery numbers: [7, 15, 23, 38, 49] (varies)O segundo argumento de sample() especifica quantos itens selecionar. O número deve ser menor ou igual ao tamanho da sequência — você não pode selecionar mais itens do que existem disponíveis.
39.1.5) Embaralhando Sequências com shuffle()
A função shuffle() reordena aleatoriamente os elementos de uma lista no lugar (modificando a lista original):
import random
# Embaralhar um baralho de cartas
cards = ["A♠", "K♠", "Q♠", "J♠", "10♠", "9♠", "8♠", "7♠"]
print(f"Original: {cards}")
random.shuffle(cards)
print(f"Shuffled: {cards}") # Output: Shuffled: ['Q♠', '7♠', 'A♠', '10♠', '9♠', 'J♠', 'K♠', '8♠'] (varies)
# Embaralhar perguntas do quiz para uma ordem aleatória
questions = ["Question 1", "Question 2", "Question 3", "Question 4"]
random.shuffle(questions)
print(f"Randomized order: {questions}") # Output: Randomized order: ['Question 3', 'Question 1', 'Question 4', 'Question 2'] (varies)39.2) Trabalhando com Datas e Horários
O módulo datetime fornece classes para trabalhar com datas, horários e intervalos de tempo. Isso é essencial para agendamento, logging, cálculo de durações e qualquer aplicação que precise acompanhar quando as coisas acontecem.
39.2.1) Obtendo a Data e Hora Atuais
A classe datetime representa um ponto específico no tempo com componentes de data e hora:
from datetime import datetime
# Obter a data e hora atuais
now = datetime.now()
print(f"Current datetime: {now}")
# Output: Current datetime: 2026-01-02 14:30:45.123456
# Acessar componentes individuais
print(f"Year: {now.year}") # Output: Year: 2026
print(f"Month: {now.month}") # Output: Month: 1
print(f"Day: {now.day}") # Output: Day: 2
print(f"Hour: {now.hour}") # Output: Hour: 14
print(f"Minute: {now.minute}") # Output: Minute: 30
print(f"Second: {now.second}") # Output: Second: 45Para apenas a data (sem hora), use a classe date:
from datetime import date
# Obter a data de hoje
today = date.today()
print(f"Today: {today}") # Output: Today: 2026-01-02
print(f"Year: {today.year}") # Output: Year: 2026
print(f"Month: {today.month}") # Output: Month: 1
print(f"Day: {today.day}") # Output: Day: 239.2.2) Criando Datas e Horários Específicos
Você pode criar objetos datetime e date para pontos específicos no tempo:
from datetime import datetime, date
# Criar uma data específica
birthday = date(1995, 7, 15)
print(f"Birthday: {birthday}") # Output: Birthday: 1995-07-15
# Criar um datetime específico
meeting = datetime(2026, 3, 15, 14, 30) # March 15, 2026 at 2:30 PM
print(f"Meeting: {meeting}") # Output: Meeting: 2026-03-15 14:30:00Isso é útil para representar prazos, compromissos, datas históricas ou qualquer ponto fixo no tempo:
from datetime import date
# Datas importantes em um projeto
project_start = date(2026, 1, 15)
project_end = date(2026, 6, 30)
print(f"Project duration: {project_start} to {project_end}")
# Output: Project duration: 2026-01-15 to 2026-06-3039.2.3) Calculando Diferenças de Tempo com timedelta
A classe timedelta representa uma duração — a diferença entre duas datas ou horários. Você pode usá-la para calcular quanto tempo passou ou para adicionar/subtrair tempo de datas:
from datetime import date, timedelta
# Calcular idade
birth_date = date(1995, 7, 15)
today = date(2026, 1, 2)
age_delta = today - birth_date
print(f"Days since birth: {age_delta.days}") # Output: Days since birth: 11128
print(f"Years (approximate): {age_delta.days // 365}") # Output: Years (approximate): 30Quando você subtrai uma data de outra, você obtém um objeto timedelta. O atributo days informa o número de dias nessa duração.
Você também pode criar objetos timedelta diretamente para representar durações específicas:
from datetime import date, timedelta
# Adicionar dias a uma data
today = date(2026, 1, 2)
one_week = timedelta(days=7)
next_week = today + one_week
print(f"Today: {today}") # Output: Today: 2026-01-02
print(f"Next week: {next_week}") # Output: Next week: 2026-01-09
# Subtrair dias de uma data
thirty_days_ago = today - timedelta(days=30)
print(f"30 days ago: {thirty_days_ago}") # Output: 30 days ago: 2025-12-03timedelta pode representar dias, segundos, microssegundos, milissegundos, minutos, horas e semanas:
from datetime import datetime, timedelta
# Calcular um prazo
now = datetime(2026, 1, 2, 14, 30)
deadline = now + timedelta(hours=48, minutes=30)
print(f"Current time: {now}") # Output: Current time: 2026-01-02 14:30:00
print(f"Deadline: {deadline}") # Output: Deadline: 2026-01-04 15:00:00
# Calcular tempo restante
time_left = deadline - now
print(f"Hours remaining: {time_left.total_seconds() / 3600}") # Output: Hours remaining: 48.5O método total_seconds() converte toda a duração para segundos, que você pode então converter para horas, minutos ou qualquer outra unidade.
Aqui vai um exemplo prático calculando marcos de um projeto:
from datetime import date, timedelta
# Planejamento do projeto
project_start = date(2026, 1, 15)
sprint_duration = timedelta(weeks=2)
sprint_1_end = project_start + sprint_duration
sprint_2_end = sprint_1_end + sprint_duration
sprint_3_end = sprint_2_end + sprint_duration
print(f"Sprint 1: {project_start} to {sprint_1_end}")
# Output: Sprint 1: 2026-01-15 to 2026-01-29
print(f"Sprint 2: {sprint_1_end} to {sprint_2_end}")
# Output: Sprint 2: 2026-01-29 to 2026-02-12
print(f"Sprint 3: {sprint_2_end} to {sprint_3_end}")
# Output: Sprint 3: 2026-02-12 to 2026-02-2639.2.4) Comparando Datas e Horários
Objetos date e datetime podem ser comparados usando operadores de comparação padrão:
from datetime import date
# Comparar datas
date1 = date(2026, 1, 15)
date2 = date(2026, 2, 20)
date3 = date(2026, 1, 15)
print(date1 < date2) # Output: True
print(date1 == date3) # Output: True
print(date2 > date1) # Output: TrueIsso é útil para verificar prazos, validar intervalos de datas e ordenar datas:
from datetime import date
# Verificar se uma data está no passado
event_date = date(2025, 12, 25)
today = date(2026, 1, 2)
if event_date < today:
print("This event has already passed") # Output: This event has already passed
else:
print("This event is upcoming")
# Ordenar uma lista de datas
important_dates = [
date(2026, 3, 15),
date(2026, 1, 10),
date(2026, 2, 28)
]
important_dates.sort()
print("Dates in order:") # Output: Dates in order:
for d in important_dates:
print(f" {d}")
# Output:
# 2026-01-10
# 2026-02-28
# 2026-03-1539.2.5) Formatando Datas e Horários com strftime()
O método strftime() (string format time) converte datas e horários em strings formatadas. Você especifica o formato usando códigos especiais:
from datetime import datetime
now = datetime(2026, 1, 2, 14, 30, 45)
# Formatos comuns de data
print(now.strftime("%Y-%m-%d")) # Output: 2026-01-02
print(now.strftime("%m/%d/%Y")) # Output: 01/02/2026
print(now.strftime("%B %d, %Y")) # Output: January 02, 2026
print(now.strftime("%A, %B %d, %Y")) # Output: Friday, January 02, 2026
# Formatos comuns de hora
print(now.strftime("%H:%M:%S")) # Output: 14:30:45
print(now.strftime("%I:%M %p")) # Output: 02:30 PM
# Formatos combinados
print(now.strftime("%Y-%m-%d %H:%M:%S")) # Output: 2026-01-02 14:30:45
print(now.strftime("%B %d, %Y at %I:%M %p")) # Output: January 02, 2026 at 02:30 PMCódigos de formato comuns:
| Código | Descrição | Exemplo |
|---|---|---|
%Y | Ano com século | 2026 |
%m | Mês como número com zero à esquerda (01-12) | 01 |
%d | Dia como número com zero à esquerda (01-31) | 02 |
%B | Nome completo do mês | January |
%b | Nome abreviado do mês | Jan |
%A | Nome completo do dia da semana | Friday |
%a | Nome abreviado do dia da semana | Fri |
%H | Hora no formato 24h (00-23) | 14 |
%I | Hora no formato 12h (01-12) | 02 |
%M | Minuto (00-59) | 30 |
%S | Segundo (00-59) | 45 |
%p | AM/PM | PM |
Aqui vai um exemplo prático criando uma entrada de log:
from datetime import datetime
def log_event(message):
"""Log an event with a timestamp"""
now = datetime.now()
timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}")
log_event("User logged in")
# Output: [2026-01-02 14:30:45] User logged in
log_event("File uploaded successfully")
# Output: [2026-01-02 14:30:45] File uploaded successfully39.2.6) Fazendo Parse de Datas a Partir de Strings com strptime()
A função strptime() (string parse time) converte strings formatadas de volta em objetos datetime. Você especifica os mesmos códigos de formato para dizer ao Python como interpretar a string:
from datetime import datetime
# Fazer parse de diferentes formatos de data
date_str1 = "2026-01-15"
date1 = datetime.strptime(date_str1, "%Y-%m-%d")
print(f"Parsed: {date1}") # Output: Parsed: 2026-01-15 00:00:00
date_str2 = "January 15, 2026"
date2 = datetime.strptime(date_str2, "%B %d, %Y")
print(f"Parsed: {date2}") # Output: Parsed: 2026-01-15 00:00:00
# Fazer parse de datetime com hora
datetime_str = "2026-01-15 14:30:00"
dt = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S")
print(f"Parsed: {dt}") # Output: Parsed: 2026-01-15 14:30:00Isso é essencial ao ler datas de arquivos, entrada do usuário ou fontes de dados externas:
from datetime import datetime
# Fazer parse da entrada do usuário
user_input = "03/15/2026"
try:
event_date = datetime.strptime(user_input, "%m/%d/%Y")
print(f"Event scheduled for: {event_date.strftime('%B %d, %Y')}")
# Output: Event scheduled for: March 15, 2026
except ValueError:
print("Invalid date format. Please use MM/DD/YYYY")Importante: A string de formato deve corresponder exatamente à string de entrada, ou você vai receber um ValueError:
from datetime import datetime
# Isso vai falhar - o formato não corresponde
try:
datetime.strptime("2026-01-15", "%m/%d/%Y") # Wrong format
except ValueError as e:
print(f"Error: {e}")
# Output: Error: time data '2026-01-15' does not match format '%m/%d/%Y'39.3) Lendo e Escrevendo Dados JSON
JSON (JavaScript Object Notation) é um formato de texto para armazenar e trocar dados estruturados. É o formato mais comum para APIs web, arquivos de configuração e troca de dados entre programas. O módulo json do Python facilita a conversão entre estruturas de dados do Python e texto JSON.
39.3.1) Entendendo a Estrutura do JSON
JSON se parece com dicionários e listas Python, mas com algumas diferenças:
JSON suporta estes tipos de dados:
- Objetos (como dicionários Python):
{"name": "Alice", "age": 30} - Arrays (como listas Python):
[1, 2, 3, 4] - Strings:
"hello"(deve usar aspas duplas) - Números:
42,3.14 - Booleanos:
true,false(minúsculos) - Nulo:
null(comoNonedo Python)
Principais diferenças em relação ao Python:
- JSON usa
true/false/nullem vez deTrue/False/Nonedo Python - Strings em JSON devem usar aspas duplas (
"text"), não aspas simples - JSON não oferece suporte direto a tuplas, sets ou objetos personalizados
Veja como são dados JSON:
{
"name": "Alice Johnson",
"age": 30,
"email": "alice@example.com",
"is_active": true,
"scores": [85, 92, 78, 95],
"address": {
"street": "123 Main St",
"city": "Springfield",
"zip": "12345"
}
}Observação: Isso é texto JSON puro, não código Python. Repare no true em minúsculas e no uso de aspas duplas.
39.3.2) Convertendo Dados Python para JSON com dumps()
A função dumps() (dump string) converte estruturas de dados Python em strings formatadas em JSON:
import json
student = {
"name": "Alice Johnson",
"age": 30,
"email": "alice@example.com",
"is_active": True,
"scores": [85, 92, 78, 95]
}
# Converter um dicionário para JSON
json_string = json.dumps(student)
print(json_string)
# Output: {"name": "Alice Johnson", "age": 30, "email": "alice@example.com", "is_active": true, "scores": [85, 92, 78, 95]}
print(type(json_string)) # Output: <class 'str'>Repare como o True do Python virou true do JSON na saída. A função dumps() lida automaticamente com essas conversões.
Para uma saída mais legível, use o parâmetro indent:
import json
student = {
"name": "Alice Johnson",
"age": 30,
"scores": [85, 92, 78, 95]
}
# Imprimir de forma bonita com indentação
json_string = json.dumps(student, indent=2)
print(json_string)
# Output:
# {
# "name": "Alice Johnson",
# "age": 30,
# "scores": [
# 85,
# 92,
# 78,
# 95
# ]
# }O parâmetro indent especifica quantos espaços usar para cada nível de indentação. Isso deixa o JSON bem mais fácil de ler, especialmente para estruturas complexas aninhadas.
39.3.3) Convertendo JSON para Dados Python com loads()
A função loads() (load string) converte strings formatadas em JSON de volta em estruturas de dados Python:
import json
# String JSON (como você poderia receber de uma API web)
json_string = '{"name": "Bob Smith", "age": 25, "scores": [90, 88, 92]}'
# Converter para dicionário Python
student = json.loads(json_string)
print(student) # Output: {'name': 'Bob Smith', 'age': 25, 'scores': [90, 88, 92]}
print(type(student)) # Output: <class 'dict'>
# Acessar os dados como qualquer dicionário Python
print(f"Name: {student['name']}") # Output: Name: Bob Smith
print(f"Average score: {sum(student['scores']) / len(student['scores'])}")
# Output: Average score: 90.0true, false e null do JSON são convertidos automaticamente para True, False e None do Python:
import json
json_string = '{"active": true, "verified": false, "middle_name": null}'
data = json.loads(json_string)
print(data) # Output: {'active': True, 'verified': False, 'middle_name': None}
print(type(data["active"])) # Output: <class 'bool'>
print(type(data["middle_name"])) # Output: <class 'NoneType'>39.3.4) Escrevendo JSON em Arquivos com dump()
A função dump() escreve dados Python diretamente em um arquivo no formato JSON:
import json
# Registros de alunos
students = [
{"name": "Alice", "age": 20, "gpa": 3.8},
{"name": "Bob", "age": 22, "gpa": 3.5},
{"name": "Charlie", "age": 21, "gpa": 3.9}
]
# Escrever em um arquivo JSON
with open("students.json", "w") as file:
json.dump(students, file, indent=2)
print("Data written to students.json")
# Output: Data written to students.jsonDepois de executar esse código, o arquivo students.json contém:
[
{
"name": "Alice",
"age": 20,
"gpa": 3.8
},
{
"name": "Bob",
"age": 22,
"gpa": 3.5
},
{
"name": "Charlie",
"age": 21,
"gpa": 3.9
}
]Por que usar dump() em vez de dumps()? A função dump() escreve diretamente em um arquivo, o que é mais eficiente do que converter para uma string primeiro e depois escrever a string. Use dump() para arquivos e dumps() quando você precisar do JSON como uma string (por exemplo, para enviar pela rede).
39.3.5) Lendo JSON de Arquivos com load()
A função load() lê dados JSON de um arquivo e os converte para estruturas de dados Python:
import json
# Ler do arquivo JSON que criamos anteriormente
with open("students.json", "r") as file:
students = json.load(file)
print(f"Loaded {len(students)} students") # Output: Loaded 3 students
# Trabalhar com os dados
for student in students:
print(f"{student['name']}: GPA {student['gpa']}")
# Output:
# Alice: GPA 3.8
# Bob: GPA 3.5
# Charlie: GPA 3.939.3.6) Lidando com Erros de JSON
Ao trabalhar com JSON, você pode encontrar dados inválidos. Sempre trate erros potenciais:
import json
# JSON inválido - faltando aspas de fechamento
invalid_json = '{"name": "Alice", "age": 30'
try:
data = json.loads(invalid_json)
except json.JSONDecodeError as e:
print(f"Invalid JSON: {e}")
# Output: Invalid JSON: Expecting ',' delimiter: line 1 column 28 (char 27)Isso é especialmente importante ao ler JSON de fontes externas (arquivos, APIs web, entrada do usuário) em que você não pode garantir que os dados sejam válidos:
import json
def load_config(filename):
"""Carregar configuração de um arquivo JSON com tratamento de erros"""
try:
with open(filename, "r") as file:
config = json.load(file)
return config
except FileNotFoundError:
print(f"Config file '{filename}' not found")
return None
except json.JSONDecodeError as e:
print(f"Invalid JSON in '{filename}': {e}")
return None
# Tentar carregar a configuração
config = load_config("config.json")
if config:
print(f"Configuration loaded: {config}")
else:
print("Using default configuration")39.3.7) Exemplo Prático de JSON: Salvando e Carregando o Estado da Aplicação
Aqui vai um exemplo completo mostrando como salvar e carregar dados da aplicação:
import json
def save_game_state(filename, player_data):
"""Salvar o estado do jogo em um arquivo JSON"""
with open(filename, "w") as file:
json.dump(player_data, file, indent=2)
print(f"Game saved to {filename}")
def load_game_state(filename):
"""Carregar o estado do jogo de um arquivo JSON"""
try:
with open(filename, "r") as file:
player_data = json.load(file)
print(f"Game loaded from {filename}")
return player_data
except FileNotFoundError:
print("No saved game found")
return None
# Dados do jogo
player = {
"name": "Hero",
"level": 5,
"health": 85,
"inventory": ["sword", "shield", "potion"],
"position": {"x": 10, "y": 20}
}
# Salvar o jogo
save_game_state("savegame.json", player)
# Output: Game saved to savegame.json
# Mais tarde, carregar o jogo
loaded_player = load_game_state("savegame.json")
# Output: Game loaded from savegame.json
if loaded_player:
print(f"Welcome back, {loaded_player['name']}!")
print(f"Level: {loaded_player['level']}, Health: {loaded_player['health']}")
# Output:
# Welcome back, Hero!
# Level: 5, Health: 8539.4) Containers Práticos em collections
O módulo collections fornece tipos de container especializados que estendem os containers embutidos do Python (listas, dicionários, sets) com funcionalidade extra. Esses containers resolvem problemas comuns de forma mais elegante do que usar estruturas de dados básicas.
39.4.1) Contando Itens com Counter
A classe Counter foi projetada para contar objetos hasheáveis. Ela é uma subclasse de dicionário que armazena itens como chaves e suas contagens como valores.
O que Counter aceita como entrada:
- Qualquer iterável (lista, string, tupla, etc.)
- Outro dicionário com contagens
- Argumentos nomeados (keyword arguments) com contagens
O que Counter armazena:
- Um dicionário em que as chaves são os itens e os valores são suas contagens
- Exemplo:
Counter(['a', 'b', 'a'])armazena{'a': 2, 'b': 1}
Vantagem principal sobre dicionários comuns:
- Retorna 0 para chaves ausentes em vez de levantar
KeyError - Fornece métodos específicos para contagem, como
most_common() - Suporta operações aritméticas entre counters
Uso Básico
from collections import Counter
# Contar letras em uma palavra
word = "mississippi"
letter_counts = Counter(word)
print(letter_counts)
# Output: Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
# Acessar contagens como um dicionário
print(f"Number of 'i's: {letter_counts['i']}")
# Output: Number of 'i's: 4
print(f"Number of 'z's: {letter_counts['z']}")
# Output: Number of 'z's: 0 (returns 0 for missing keys, no KeyError!)Criando Counters a Partir de Diferentes Fontes
from collections import Counter
# A partir de uma lista
votes = ["Alice", "Bob", "Alice", "Charlie", "Alice", "Bob", "Alice"]
vote_counts = Counter(votes)
print(vote_counts)
# Output: Counter({'Alice': 4, 'Bob': 2, 'Charlie': 1})
# A partir de uma string (conta cada caractere)
letter_counts = Counter("hello")
print(letter_counts)
# Output: Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
# A partir de um dicionário
existing_counts = {'apple': 3, 'banana': 2}
fruit_counts = Counter(existing_counts)
print(fruit_counts)
# Output: Counter({'apple': 3, 'banana': 2})
# A partir de argumentos nomeados
color_counts = Counter(red=5, blue=3, green=2)
print(color_counts)
# Output: Counter({'red': 5, 'blue': 3, 'green': 2})Encontrando Itens Mais Comuns com most_common()
Assinatura do método: most_common(n=None)
Parâmetros:
n(opcional): Número de itens mais comuns a retornar- Se
nfor omitido ouNone, retorna todos os itens
Retorna:
- Uma lista de tuplas
(item, count) - Ordenada pela contagem, do maior para o menor
- Se as contagens forem iguais, os itens ficam na ordem em que foram encontrados primeiro
from collections import Counter
# Analisar frequência de palavras no texto
text = "the quick brown fox jumps over the lazy dog the fox"
words = text.split()
word_counts = Counter(words)
# Obter as 3 palavras mais comuns
top_3 = word_counts.most_common(3)
print(top_3)
# Output: [('the', 3), ('fox', 2), ('quick', 1)]Operações Aritméticas em Counters
Você pode somar, subtrair e realizar outras operações em objetos Counter:
from collections import Counter
# Contar itens em dois grupos
group1 = Counter(["apple", "banana", "apple", "orange"])
print(group1)
# Output: Counter({'apple': 2, 'banana': 1, 'orange': 1})
group2 = Counter(["banana", "banana", "grape", "apple"])
print(group2)
# Output: Counter({'banana': 2, 'grape': 1, 'apple': 1})
# Somar as contagens
combined = group1 + group2
print(combined)
# Output: Counter({'apple': 3, 'banana': 3, 'orange': 1, 'grape': 1})
# Subtrair as contagens (mantém apenas resultados positivos)
difference = group1 - group2
print(difference)
# Output: Counter({'apple': 1, 'orange': 1})
# banana: 1 - 2 = -1 (negative, so excluded)
# grape: not in group1, so excludedExemplo Prático: Analisando Notas de Alunos
from collections import Counter
# Distribuição de notas
grades = ["A", "B", "A", "C", "B", "A", "B", "D", "A", "B", "C", "A"]
grade_counts = Counter(grades)
print(f"Total students: {len(grades)}")
# Output: Total students: 12
print("\nGrade Distribution:")
for grade, count in grade_counts.most_common():
percentage = (count / len(grades)) * 100
bar = "█" * count
print(f" {grade}: {count} students ({percentage:4.1f}%) {bar}")
# Output:
# Grade Distribution:
# A: 5 students (41.7%) █████
# B: 4 students (33.3%) ████
# C: 2 students (16.7%) ██
# D: 1 students ( 8.3%) █39.4.2) Dicionários com Valores Padrão Usando defaultdict
A classe defaultdict é uma subclasse de dicionário que cria automaticamente entradas com um valor padrão quando você acessa uma chave ausente. Isso elimina a necessidade de verificar se as chaves existem antes de usá-las.
O que defaultdict aceita como entrada:
- Uma função default factory (obrigatória): Um callable que retorna o valor padrão para chaves ausentes
- Quaisquer argumentos que um
dictnormal aceita (pares chave-valor, outro dicionário, argumentos nomeados)
Vantagem principal sobre dicionários comuns:
- Não precisa verificar se uma chave existe antes de usá-la
- Inicializa automaticamente chaves ausentes com um valor padrão
- Código mais limpo e legível para operações de agrupamento, contagem e acumulação
Entendendo a Default Factory
Quando você cria um defaultdict, você deve fornecer uma default factory — um callable (função) que não recebe argumentos e retorna o valor padrão. Default factories comuns:
int- retorna0(útil para contagem)list- retorna[](útil para agrupar itens)set- retornaset()(útil para coletar itens únicos)str- retorna''(útil para concatenação de strings)lambda: value- retorna um valor padrão personalizado
from collections import defaultdict
# Diferentes default factories
counts = defaultdict(int) # Chaves ausentes retornam 0
groups = defaultdict(list) # Chaves ausentes retornam []
unique = defaultdict(set) # Chaves ausentes retornam set()
custom = defaultdict(lambda: "N/A") # Chaves ausentes retornam "N/A"
# Testar com chaves ausentes
print(counts['missing']) # Output: 0
print(groups['missing']) # Output: []
print(unique['missing']) # Output: set()
print(custom['missing']) # Output: N/AUso Básico: Contando com defaultdict
Compare dicionário normal vs defaultdict para contagem:
from collections import defaultdict
word = "mississippi"
# Dicionário normal - precisa verificar se a chave existe
regular_dict = {}
for letter in word:
if letter not in regular_dict:
regular_dict[letter] = 0
regular_dict[letter] += 1
print(regular_dict)
# Output: {'m': 1, 'i': 4, 's': 4, 'p': 2}
# defaultdict - cria automaticamente entradas com valor padrão
letter_counts = defaultdict(int) # int() retorna 0
for letter in word:
letter_counts[letter] += 1 # Não precisa verificar se a chave existe!
print(dict(letter_counts))
# Output: {'m': 1, 'i': 4, 's': 4, 'p': 2}Como funciona:
- Quando você acessa
letter_counts[letter]para uma letra nova, odefaultdictchamaint()que retorna0 - A chave é criada com valor
0, então+= 1faz virar1 - Para chaves existentes, ele se comporta como um dicionário normal
Agrupando Itens com defaultdict(list)
Um caso de uso comum é agrupar itens em categorias:
from collections import defaultdict
students = [
("Alice", "A"),
("Bob", "B"),
("Charlie", "A"),
("Diana", "C"),
("Eve", "B"),
("Frank", "A")
]
# Agrupar alunos por nota
# Com defaultdict - limpo e simples
students_by_grade = defaultdict(list)
for name, grade in students:
students_by_grade[grade].append(name)
print(dict(students_by_grade))
# Output: {'A': ['Alice', 'Charlie', 'Frank'], 'B': ['Bob', 'Eve'], 'C': ['Diana']}
# Acessar uma nota que ainda não existe
print(students_by_grade["D"]) # Output: [] (empty list, not KeyError!)Como funciona:
- Quando você acessa
students_by_grade[grade]para uma nota nova, odefaultdictchamalist()que retorna[] - A chave é criada com uma lista vazia, então
.append(name)adiciona o primeiro aluno - Para notas existentes, ele apenas adiciona na lista já existente
Criando defaultdict a Partir de um Dicionário Existente
Você pode inicializar um defaultdict com dados existentes:
from collections import defaultdict
# Começar com contagens existentes
existing_data = {'apple': 5, 'banana': 3}
# Criar defaultdict a partir de um dicionário existente
fruit_counts = defaultdict(int, existing_data)
# Adicionar mais contagens
fruit_counts['apple'] += 2 # 5 + 2 = 7
fruit_counts['orange'] += 1 # 0 + 1 = 1 (new key, starts at 0)
print(dict(fruit_counts))
# Output: {'apple': 7, 'banana': 3, 'orange': 1}Default Factory Personalizada
Você pode fornecer qualquer callable como default factory:
from collections import defaultdict
# Usar lambda para valores padrão personalizados
page_views = defaultdict(lambda: {'views': 0, 'unique': 0})
page_views['home']['views'] = 100
page_views['home']['unique'] = 75
print(page_views['home'])
# Output: {'views': 100, 'unique': 75}
print(page_views['about']) # New key gets default dictionary
# Output: {'views': 0, 'unique': 0}Observações Importantes
Acessar vs. Checar Chaves:
from collections import defaultdict
counts = defaultdict(int)
# Acessar uma chave ausente a CRIA
value = counts['missing'] # Cria 'missing' com valor 0
print('missing' in counts) # Output: True
# Para checar sem criar, use 'in' ou .get()
counts2 = defaultdict(int)
print('missing' in counts2) # Output: False (doesn't create key)
print(counts2.get('missing')) # Output: None (doesn't create key)39.5) (Opcional) Ferramentas Úteis de Iteração
O módulo itertools fornece funções para criar iteradores eficientes. Essas ferramentas ajudam você a trabalhar com sequências de formas poderosas sem criar grandes listas intermediárias.
39.5.1) Encadeando Iteráveis com chain()
A função chain() combina vários iteráveis em um único iterador que produz elementos de cada iterável em sequência.
O que chain() aceita:
- Vários iteráveis (listas, tuplas, strings etc.) como argumentos separados
O que chain() retorna:
- Um iterador que produz todos os elementos do primeiro iterável, depois todos os elementos do segundo, e assim por diante
Vantagem principal:
- Mais eficiente em memória do que concatenar com
+(não cria listas intermediárias) - Funciona com qualquer iterável, não apenas listas
from itertools import chain
# Combinar várias listas
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9]
combined = chain(list1, list2, list3)
print(list(combined)) # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]Isso é mais eficiente em memória do que concatenar listas com +, especialmente para sequências grandes:
from itertools import chain
# Processar várias fontes de dados sem criar uma grande lista combinada
students_class_a = ["Alice", "Bob", "Charlie"]
students_class_b = ["Diana", "Eve", "Frank"]
students_class_c = ["Grace", "Henry", "Iris"]
# Iterar sobre todos os alunos sem criar uma lista combinada
for student in chain(students_class_a, students_class_b, students_class_c):
print(f"Processing: {student}")
# Output:
# Processing: Alice
# Processing: Bob
# Processing: Charlie
# Processing: Diana
# Processing: Eve
# Processing: Frank
# Processing: Grace
# Processing: Henry
# Processing: IrisVocê pode encadear diferentes tipos de iteráveis:
from itertools import chain
# Encadear listas, tuplas e strings
numbers = [1, 2, 3]
letters = ("a", "b", "c")
word = "xyz"
combined = chain(numbers, letters, word)
print(list(combined)) # Output: [1, 2, 3, 'a', 'b', 'c', 'x', 'y', 'z']39.5.2) Repetindo Elementos com cycle()
A função cycle() cria um iterador infinito que cicla repetidamente pelos elementos de um iterável.
O que cycle() aceita:
- Um único iterável (lista, tupla, string etc.)
O que cycle() retorna:
- Um iterador infinito que produz elementos do iterável repetidamente
- Depois de chegar ao fim, recomeça do início
Principais características:
- Cria um iterador infinito — nunca para por conta própria
- Deve ser usado com uma condição de parada (contador,
breakouzip()) - Eficiente em memória: não cria cópias dos dados
from itertools import cycle
# Criar um ciclo infinito de cores
colors = cycle(["red", "green", "blue"])
# Pegar as primeiras 10 cores
for i, color in enumerate(colors):
if i >= 10:
break
print(f"Item {i}: {color}")
# Output:
# Item 0: red
# Item 1: green
# Item 2: blue
# Item 3: red
# Item 4: green
# Item 5: blue
# Item 6: red
# Item 7: green
# Item 8: blue
# Item 9: redAviso: cycle() cria um iterador infinito. Sempre use com uma condição de parada (como um contador ou uma instrução break), senão você vai criar um loop infinito.
Um caso de uso prático é alternar entre valores:
from itertools import cycle
# Alternar entre duas cores de fundo para linhas de tabela
row_colors = cycle(["white", "lightgray"])
rows = ["Row 1", "Row 2", "Row 3", "Row 4", "Row 5"]
for row, color in zip(rows, row_colors):
print(f"{row}: background-color: {color}")
# Output:
# Row 1: background-color: white
# Row 2: background-color: lightgray
# Row 3: background-color: white
# Row 4: background-color: lightgray
# Row 5: background-color: whiteAqui usamos zip() (que aprendemos no Capítulo 37) para parear cada linha com uma cor. O iterador cycle() repete automaticamente as cores conforme necessário.
39.5.3) Combinando chain() e cycle()
Você pode combinar funções de itertools para padrões mais complexos:
from itertools import chain, cycle
# Criar um padrão que cicla por várias sequências
pattern1 = [1, 2, 3]
pattern2 = [10, 20]
# Encadear os padrões e então ciclar o resultado
combined_pattern = cycle(chain(pattern1, pattern2))
# Pegar os primeiros 12 valores
for i, value in enumerate(combined_pattern):
if i >= 12:
break
print(value, end=" ")
# Output: 1 2 3 10 20 1 2 3 10 20 1 2
print() # Output: NewlineIsso cria um padrão repetido: 1, 2, 3, 10, 20, 1, 2, 3, 10, 20, ...
Aqui vai um exemplo prático criando uma escala rotativa:
from itertools import cycle
# Criar uma escala rotativa para membros do time
team_members = ["Alice", "Bob", "Charlie"]
schedule = cycle(team_members)
# Atribuir tarefas aos membros do time em rotação
tasks = [
"Review code",
"Write tests",
"Update documentation",
"Fix bug #123",
"Implement feature X",
"Deploy to staging"
]
print("Task Assignments:")
for task, assignee in zip(tasks, schedule):
print(f" {assignee}: {task}")
# Output:
# Task Assignments:
# Alice: Review code
# Bob: Write tests
# Charlie: Update documentation
# Alice: Fix bug #123
# Bob: Implement feature X
# Charlie: Deploy to stagingNeste capítulo, exploramos cinco módulos essenciais da biblioteca padrão que estendem as capacidades do Python:
random: Gerar números aleatórios, fazer seleções aleatórias e embaralhar sequências — essencial para simulações, jogos e testesdatetime: Trabalhar com datas, horários e durações — calcular idades, agendar eventos e formatar timestampsjson: Trocar dados com outros programas usando o formato JSON universal — salvar estado da aplicação, trabalhar com APIs web e armazenar configuraçãocollections: Usar containers especializados comoCounterpara contagem edefaultdictpara criação automática de chavesitertools: Criar iteradores eficientes comchain()para combinar sequências ecycle()para repetir padrões
Esses módulos fazem parte da biblioteca padrão do Python — eles estão sempre disponíveis, são bem testados e resolvem problemas comuns de programação de forma elegante. À medida que você construir programas mais complexos, vai perceber que recorre a essas ferramentas com frequência. Eles representam a filosofia do Python de “baterias incluídas” (batteries included) — fornecendo soluções poderosas e prontas para uso para tarefas do dia a dia em programação.