Prática de Ramificações e Laços
Prática de Ramificações e Laços
Aprendemos muita teoria — agora é hora de construir alguns projetos reais. Esta é uma lição prática. Usando if statements, for loops, while loops, break, continue e outros conceitos que aprendemos, vamos construir quatro programas completos passo a passo.
Para cada projeto, analisaremos os requisitos, escreveremos o código e discutiremos possíveis melhorias.
Projeto 1: Jogo de Adivinhação de Números (Melhorado)
Na Lição 08, escrevemos um jogo básico de adivinhação. Agora vamos melhorá-lo com seleção de dificuldade, limites de tentativas e um recurso de "jogar novamente."
Requisitos
1. Jogador seleciona dificuldade: Fácil (1-50, ilimitado), Normal (1-100, 10 tentativas), Difícil (1-200, 7 tentativas)
2. Sistema gera aleatoriamente um número alvo
3. Após cada palpite, dica "muito alto" ou "muito baixo" e exibe tentativas restantes
4. Após acertar ou esgotar tentativas, pergunte "jogar novamente?"
5. Digite q para sair
Código Completo (⭐⭐⭐)
Exemplo: Jogo de Adivinhação de Números
import random
print("=" * 30)
print("Jogo de Adivinhação (Melhorado)")
print("=" * 30)
while True: # Laço externo: controla "jogar novamente"
# Seleciona dificuldade
print("\nSelecione a dificuldade:")
print("1. Fácil (1~50, ilimitado)")
print("2. Normal (1~100, 10 tentativas)")
print("3. Difícil (1~200, 7 tentativas)")
choice = input("Digite 1/2/3: ")
if choice == "1":
max_num = 50
max_attempts = float("inf") # Ilimitado
elif choice == "2":
max_num = 100
max_attempts = 10
elif choice == "3":
max_num = 200
max_attempts = 7
else:
print("Escolha inválida, usando Normal como padrão")
max_num = 100
max_attempts = 10
# Gera número alvo
target = random.randint(1, max_num)
attempts = 0
print(f"\nNúmero gerado entre 1~{max_num}. Comece a adivinhar!")
# Laço interno: lógica principal do jogo
while True:
# Verifica se as tentativas acabaram
if attempts >= max_attempts:
print(f"\nTentativas esgotadas! A resposta era {target}")
break
# Obtém palpite do jogador
guess_str = input(f"{max_attempts - attempts} tentativas restantes, digite seu palpite: ")
if guess_str.lower() == "q":
print("Saindo do jogo.")
max_attempts = -1 # Flag para notificar laço externo
break
# Valida entrada
if not guess_str.isdigit():
print("Por favor, digite um número válido!")
continue
guess = int(guess_str)
attempts += 1
# Verifica palpite
if guess < target:
print("Muito baixo, tente mais alto!")
elif guess > target:
print("Muito alto, tente mais baixo!")
else:
print(f"\nParabéns! A resposta era {target}!")
print(f"Você acertou em {attempts} tentativas.")
break
# Verifica se devemos sair completamente
if max_attempts == -1: # Jogador digitou q
break
# Pergunta por outra rodada
again = input("\nJogar novamente? (s/n): ")
if again.lower() != "s":
print("Obrigado por jogar, até logo!")
break
Destaque de design: O laço externo controla "jogar novamente," o laço interno controla o "processo de adivinhação." A flag
max_attempts = -1resolve o problema de sair de ambos os laços quando o jogador digita q. Uma abordagem mais elegante seria encapsular a lógica do jogo em uma função e usarreturnpara sair de uma vez.
Projeto 2: Tabuada de Multiplicação (Múltiplos Estilos)
Na Lição 08, imprimimos uma tabuada padrão. Um bom programador deve ser capaz de controlar flexivelmente estruturas de laço para exibir qualquer estilo.
Estilo 1: Triângulo Inferior Padrão (⭐⭐)
Exemplo: Triângulo Inferior Padrão
print("=== Triângulo Inferior Padrão ===")
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}x{i}={i*j}", end="\t")
print()
Estilo 2: Retângulo Completo (⭐⭐)
Exemplo: Retângulo Completo
print("=== Retângulo Completo ===")
for i in range(1, 10):
for j in range(1, 10):
print(f"{j}x{i}={i*j}", end="\t")
print()
Estilo 3: Triângulo Superior (⭐⭐⭐)
Exemplo: Triângulo Superior
print("=== Triângulo Superior ===")
for i in range(1, 10):
# Imprime espaços iniciais para alinhamento
for k in range(1, i):
print(end="\t\t")
# Imprime fórmulas de multiplicação
for j in range(i, 10):
print(f"{i}x{j}={i*j}", end="\t")
print()
Saída:
=== Triângulo Superior ===
1x1=1 1x2=2 1x3=3 ... 1x9=9
2x2=4 2x3=6 ... 2x9=18
3x3=9 ... 3x9=27
...
9x9=81
Insight principal: O desafio do triângulo superior é o "alinhamento de espaços" — cada linha precisa de
(i-1) * 2caracteres de tabulação de indentação. Isso usa dois laços internos: o primeiro imprime espaços, o segundo imprime as fórmulas.
Projeto 3: Calculadora Simples (Melhorada)
Nos exercícios da Lição 08, escrevemos uma calculadora básica. Agora vamos fazer uma versão melhorada suportando operações contínuas com histórico.
Requisitos
1. Começa com resultado atual = 0
2. Usuário digita: operador número, ex.: "+ 5"
3. Operadores suportados: + - * / ** // % clear exit
4. clear redefine o resultado para 0
5. exit sai do programa
6. Após cada operação, mostre o resultado atual e o histórico
Código Completo (⭐⭐⭐)
Exemplo: Calculadora Melhorada
print("=" * 40)
print("Calculadora Melhorada")
print("Formato: operador número, ex.: + 5")
print("Suportados: + - * / ** // %")
print("Comandos especiais: clear reset exit quit")
print("=" * 40)
result = 0.0
history = [] # Armazena histórico de operações
while True:
# Exibe resultado atual
print(f"\nResultado atual: {result}")
# Obtém entrada do usuário
cmd = input(">>> ").strip()
# Trata comandos especiais
if cmd.lower() in ("exit", "quit"):
print("Obrigado por usar!")
break
if cmd.lower() == "clear":
result = 0.0
history.clear()
print("Redefinido para 0")
continue
# Analisa comandos de operação regulares
parts = cmd.split()
if len(parts) != 2:
print("Formato inválido! Digite: operador número")
continue
op, num_str = parts
# Valida número
if not num_str.replace(".", "").isdigit() or num_str.count(".") > 1:
print("Número inválido!")
continue
num = float(num_str)
# Executa operação
old_result = result
if op == "+":
result += num
elif op == "-":
result -= num
elif op == "*":
result *= num
elif op == "/":
if num == 0:
print("Erro: Não é possível dividir por zero!")
continue
result /= num
elif op == "**":
result **= num
elif op == "//":
if num == 0:
print("Erro: Não é possível dividir por zero!")
continue
result //= num
elif op == "%":
if num == 0:
print("Erro: Não é possível dividir por zero!")
continue
result %= num
else:
print(f"Operador inválido: {op}")
continue
# Registra histórico
history.append(f"{old_result} {op} {num} = {result}")
# Exibe resultado
print(f"= {result}")
# Mostra últimas 3 entradas do histórico
if len(history) >= 1:
print("--- Histórico Recente ---")
for item in history[-3:]:
print(f" {item}")
Execução de exemplo:
>>> + 10
= 10.0
--- Histórico Recente ---
0.0 + 10.0 = 10.0
>>> * 3
= 30.0
--- Histórico Recente ---
0.0 + 10.0 = 10.0
10.0 * 3.0 = 30.0
>>> / 0
Erro: Não é possível dividir por zero!
>>> clear
Redefinido para 0
Mentalidade de programação: Este exemplo mostra a interação clássica de laços e condições —
while Truemantém o programa em execução,if-elif-elselida com várias entradas,continuepula entrada inválida, ebreaksai normalmente.
Projeto 4: Localizador de Números Primos
Permita que o usuário insira um intervalo, exiba todos os números primos dentro desse intervalo e os conte.
Requisitos
1. Usuário insere valores inicial e final
2. Programa exibe todos os primos nesse intervalo
3. Exibe 10 por linha, alinhados
4. Mostra a contagem total de primos
Código Completo (⭐⭐⭐)
Exemplo: Localizador de Números Primos
print("Localizador de Números Primos")
print("Digite um intervalo, e eu encontrarei todos os primos.")
# Obtém intervalo
start_str = input("Valor inicial (>=2): ")
end_str = input("Valor final: ")
# Valida entrada
if not (start_str.isdigit() and end_str.isdigit()):
print("Por favor, digite números inteiros positivos válidos!")
else:
start = int(start_str)
end = int(end_str)
if start < 2:
start = 2
print("Valor inicial ajustado para 2 (primos começam em 2)")
if start > end:
print("Valor inicial não pode ser maior que o valor final!")
else:
primes = [] # Armazena primos encontrados
# Verifica cada número no intervalo
for num in range(start, end + 1):
# Verifica se num é primo
is_prime = True
for i in range(2, int(num ** 0.5) + 1):
if num % i == 0:
is_prime = False
break
if is_prime:
primes.append(num)
# Exibe resultados
print(f"\nEncontrados {len(primes)} primos entre {start} e {end}:")
for i, prime in enumerate(primes, 1):
print(f"{prime:5d}", end="")
if i % 10 == 0: # Nova linha a cada 10
print()
print() # Nova linha final
Exemplo de saída:
Valor inicial (>=2): 50
Valor final: 200
Encontrados 34 primos entre 50 e 200:
53 59 61 67 71 73 79 83 89 97
101 103 107 109 113 127 131 137 139 149
151 157 163 167 173 179 181 191 193 197
199
Dica de otimização: Ao verificar se um número é primo, você não precisa dividir até
num-1— apenas atésqrt(num). Senumtem um fator maior quesqrt(num), ele deve ter um fator pareado menor quesqrt(num). Esta otimização é muito eficaz para grandes intervalos (100.000+).
Projeto 5: IMC + Verificador de Força de Senha
Este projeto reúne operadores aritméticos, operadores de comparação, operadores lógicos, condicionais e métodos de string para resolver dois problemas comuns do mundo real.
Parte 1: Índice de Massa Corporal (IMC) (⭐⭐)
IMC (Índice de Massa Corporal) é uma medida internacionalmente usada de gordura corporal. A fórmula é simples:
IMC = peso(kg) / altura(m)^2
Exemplo: Calculadora de IMC
# Calculadora de IMC
# Dados de entrada
weight = 68
height = 1.75
# Calcula IMC
bmi = weight / (height ** 2)
print("=== Índice de Massa Corporal ===")
print(f"Peso: {weight} kg")
print(f"Altura: {height} m")
print(f"IMC: {bmi:.1f}")
# Usa comparação encadeada e if-elif para determinar categoria
if bmi < 18.5:
print("Categoria: Abaixo do peso")
elif 18.5 <= bmi < 24:
print("Categoria: Normal")
elif 24 <= bmi < 28:
print("Categoria: Sobrepeso")
else:
print("Categoria: Obeso")
Saída:
=== Índice de Massa Corporal ===
Peso: 68 kg
Altura: 1.75 m
IMC: 22.2
Categoria: Normal
Dica: Comparações encadeadas como
18.5 <= bmi < 24são muito mais limpas quebmi >= 18.5 and bmi < 24.
Parte 2: Verificador de Força de Senha (⭐⭐⭐)
Escreva um programa para determinar se a senha de um usuário é segura. A força da senha depende do seu comprimento e dos tipos de caracteres que contém.
Exemplo: Verificador de Força de Senha
# Verificador de Força de Senha
password = "Py3#thon"
# Analisa características da senha
length = len(password) # Comprimento
has_digit = any(c.isdigit() for c in password) # Contém dígito
has_letter = any(c.isalpha() for c in password) # Contém letra
has_special = not password.isalnum() # Contém caractere especial
print("=== Verificador de Força de Senha ===")
print(f"Senha: {password}")
print(f"Comprimento: {length}")
print(f"Contém dígito: {has_digit}")
print(f"Contém letra: {has_letter}")
print(f"Contém caractere especial: {has_special}")
# Combina condições com operadores lógicos para determinar força
if length < 6:
strength = "Fraca"
elif length >= 10 and has_digit and has_letter and has_special:
strength = "Forte"
elif length >= 8 and has_digit and has_letter:
strength = "Média"
else:
strength = "Fraca"
print(f"Força da senha: {strength}")
Saída:
=== Verificador de Força de Senha ===
Senha: Py3#thon
Comprimento: 8
Contém dígito: True
Contém letra: True
Contém caractere especial: True
Força da senha: Média
Detalhes:
len()obtém o comprimento da string,isdigit()verifica dígitos,isalpha()verifica letras,isalnum()verifica se apenas letras e dígitos (retornaFalsese houver caracteres especiais — negado comnotse torna "contém caractere especial"). Estes métodos serão abordados sistematicamente na lição de strings.
Erros Comuns de Ramificação/Laço
Todo mundo comete erros ao escrever código, especialmente iniciantes em laços. Aqui estão as armadilhas mais típicas.
Erro 1: Laço Infinito — Esquecer de Atualizar a Variável de Condição
# Errado
n = 1
while n <= 10:
print(n)
# esqueceu n += 1 — nunca termina
# Correto
n = 1
while n <= 10:
print(n)
n += 1
Erro 2: Confundir = com ==
# Errado
if score = 100: # Isto é atribuição, não comparação!
print("Perfeito!")
# Correto
if score == 100:
print("Perfeito!")
Erro 3: Modificar uma Lista Durante a Iteração
# Errado — deletar durante iteração causa pulos
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num % 2 == 0:
numbers.remove(num)
print(numbers) # Pode não ser o que você espera
# Correto — crie uma nova lista
numbers = [1, 2, 3, 4, 5]
odd_numbers = [num for num in numbers if num % 2 != 0]
print(odd_numbers)
Erro 4: Entender Errado o Valor Final de range()
# Errado: esperando range(5) exibir 1 2 3 4 5
for i in range(5):
print(i) # Saída real: 0 1 2 3 4
# Correto
for i in range(1, 6):
print(i) # Saída: 1 2 3 4 5
Casos de Uso Comuns
| Cenário | Técnica de Laço/Ramificação | Descrição |
|---|---|---|
| Processamento de dados (filtragem, limpeza) | for + continue |
Pular dados inválidos |
| Menu de interação com usuário | while True + break |
Mostrar menu repetidamente até sair |
| Carregamento paginado | while + condição |
Até não haver mais dados |
| Busca/pesquisa | for + break + else |
Parar ao encontrar; else se não encontrado |
| Processamento em lote de arquivos | for + lógica aninhada |
Iterar cada arquivo em um diretório |
| Laço principal de jogo | while True + tratamento de eventos |
Renderização contínua e resposta a entrada |
❓ Perguntas Frequentes
P: Continuo tendo laços infinitos. O que devo verificar? R: Verifique três coisas: 1) A condição do laço algum dia se tornará
False? 2) O corpo do laço modifica a variável de condição? 3)while Truetem umbreakcorrespondente? Adicionarprint()para exibir valores-chave de variáveis é a maneira mais eficaz de depurar laços infinitos. P: Qual é mais eficiente —range()ou iterar sobre uma lista? R:range()retorna uma sequência preguiçosa sem gerar todos os números de uma vez.range(1000000)usa quase nenhuma memória, enquantolist(range(1000000))usa muita. Para grandes contagens de iteração, userange()diretamente para melhor eficiência de memória. P: O código do projeto é muito mais longo que os exemplos anteriores. Como devo lê-lo? R: Três passos: Primeiro, entenda a estrutura geral (quantos laços/condições). Segundo, entenda o fluxo principal (como as variáveis mudam). Terceiro, concentre-se nos casos extremos (validação de entrada, divisão por zero, etc.). Código bom é auto-documentado — nomes de variáveis significativos e comentários nos pontos-chave.
📖 Resumo
- Jogo de Adivinhação Melhorado: Laço externo para "jogar novamente," laço interno para "adivinhar," use
while True+breakpara gerenciamento de saída de laço multinível - Estilos de Tabuada: Controle os limites do
range()do laço interno para exibir triângulo inferior, triângulo superior, retângulo e mais - Calculadora Melhorada:
continuepara pular entrada inválida, lista para armazenar histórico,split()para analisar entrada do usuário - Localizador de Números Primos: Otimize para verificar até
sqrt(num)para eficiência;enumerate(primos, 1)para saída numerada - Dicas de Depuração: Três elementos para verificação de laço infinito, distinga
=de==, não modifique listas durante iteração
📝 Atividades
⭐: Números Narcisistas
Um "número narcisista" é um número de 3 dígitos onde a soma dos cubos de seus dígitos é igual ao próprio número. Por exemplo: 153 = 1^3 + 5^3 + 3^3.
Use um laço for para encontrar todos os números narcisistas (existem 4).
Dica: Use range(100, 1000) para iterar todos os números de 3 dígitos; use // e % para extrair dígitos das centenas, dezenas e unidades.
⭐⭐: Imprimir um Losango
Aceite um número ímpar n do usuário, depois exiba um losango feito de * no console.
Exemplo (n=5):
*
***
*
***
*
Dica: Um losango tem metade superior e inferior. Para a metade superior, faça laço i de 1 a n//2 + 1, diminuindo espaços e aumentando asteriscos.
⭐⭐⭐: Sistema de Gerenciamento de Notas de Alunos
Escreva um programa que implemente os seguintes recursos:
1. Insira notas dos alunos (digite q para parar)
2. Calcule total, média, nota mais alta e mais baixa
3. Conte alunos em cada faixa: 90-100 (Excelente), 80-89 (Bom), 70-79 (Médio), 60-69 (Aprovado), <60 (Reprovado)
4. Exiba notas ordenadas da mais alta para a mais baixa
Requisitos:
- Use laço
while Truepara coletar notas - Use uma lista para armazenar notas
- Use laço
forpara contar faixas de notas - Use
sorted(..., reverse=True)para ordenação
Este projeto aplica de forma abrangente laços, listas, ordenação e estatísticas. Completá-lo significa que você realmente domina o fluxo de controle básico do Python.



