Em Python, as estruturas de repetição são cruciais para executar blocos de código várias vezes. As principais ferramentas para isso são os laços while e for, complementados por conceitos como iteradores, compreensões de lista e expressões geradoras, que otimizam o processamento de dados.
O Laço while
O laço while permite que um bloco de código seja executado repetidamente enquanto uma condição específica for verdadeira. A execução continua até que a condição se torne falsa.
Sintaxe Básica
while condição_logica:
# Bloco de código a ser repetido
instrucao_1
instrucao_2
# ...
Exemplo de Contagem
Este exemplo demonstra um contador simples que é incrementado a cada iteração, parando quando atinge um limite.
numero_atual = 0
limite_maximo = 5
print("Iniciando contagem:")
while numero_atual < limite_maximo:
print(f"Número atual: {numero_atual}")
numero_atual += 1
print("Laço while concluído.")
Neste caso, o laço executa enquanto numero_atual to menor que limite_maximo. A cada passo, o valor é impresso e depois incrementado.
Laço Infinito
Se a condição de um laço while for sempre verdadeira, ele executará infinitamente. Isso pode ser útil para servidores ou processos que precisam estar sempre ativos, mas deve ser usado com cautela para evitar consumo excessivo de recursos e a necessidade de interromper o programa manualmente.
# while True:
# print("Este laço nunca para! Para sair, pressione Ctrl+C.")
# # Cuidado: descomentar isso criará um laço infinito!
O Laço for
O laço for é usado para iterar sobre os elementos de uma sequência (como uma lista, tupla, string) ou outros objetos iteráveis, executando um bloco de código para cada item.
Sintaxe Geral
for elemento in objeto_iteravel:
# Bloco de código a ser executado para cada item
instrucao_a
instrucao_b
# ...
Em cada iteração, elemento assume o valor do próximo item do objeto_iteravel.
Iterando Tipos de Sequência
O laço for é flexível e pode ser usado para precorrer diferentes tipos de sequências.
1. Iteração Direta pelos Itens
É a forma mais comum, onde a variável do laço recebe diretamente cada item da sequência.
cores = ["vermelho", "verde", "azul"]
for cor_atual in cores:
print(f"Uma cor vibrante: {cor_atual}.")
2. Iteração por Índice
Para acessar os itens usando seus índices, pode-se combinar range() e len().
paises = ["Brasil", "Portugal", "Japão"]
for idx_pais in range(len(paises)):
print(f"O país no índice {idx_pais} é {paises[idx_pais]}.")
3. Iteração com Item e Índice (enumerate)
A função enumerate() é ideal para obter tanto o índice quanto o valor de cada item da sequência simultaneamente.
itens_compra = ["Pão", "Leite", "Café"]
for pos, nome_item in enumerate(itens_compra):
print(f"Item {pos + 1}: {nome_item}")
Função range()
A função range() é uma geradora de sequências numéricas e é frequentemente usada em conjunto com laços for. Ela cria um objeto que representa uma sequência imutável de números.
range([início,] parada[, passo])
início(opcional): Onde a sequência começa (padrão é 0).parada(obrigatório): Onde a sequência termina (este número não é incluído).passo(opcional): O incremento entre os números (padrão é 1).
# Exemplo: Números de 5 a 8
seq_curta = list(range(5, 9))
print(f"Sequência 5-8: {seq_curta}") # Saída: [5, 6, 7, 8]
# Exemplo: Números ímpares de 1 a 10 (excluindo 10)
impares = list(range(1, 10, 2))
print(f"Ímpares 1-9: {impares}") # Saída: [1, 3, 5, 7, 9]
Funções Nativas Relacionadas a Sequências
Python oferece várias funções embutidas que facilitam a manipulação e iteração sobre sequências.
sorted(): Retorna uma nova lista com todos os itens do iterável em ordem crescente.reversed(): Retorna um iterador que acessa os itens na ordem inversa.enumerate(): Retorna pares de índice e valor para cada item, como visto anteriormente.zip(): Agrupa elementos de múltiplos iteráveis em tuplas, parando quando o iterável mais curto se esgota.
animais = ["leão", "zebra", "elefante"]
tamanhos = ["grande", "médio", "enorme"]
pesos_estimados = [180, 350, 6000] # em kg
print("Animais ordenados alfabeticamente:")
for animal_ord in sorted(animais):
print(animal_ord, end=" | ") # Saída: elefante | leão | zebra |
print("\nAnimais na ordem inversa da lista original:")
for animal_rev in reversed(animais):
print(animal_rev, end=" | ") # Saída: elefante | zebra | leão |
print("\n\nAnimais com seus índices:")
for indice_a, nome_animal in enumerate(animais):
print(f"{indice_a}: {nome_animal}")
print("\nCombinando animais, tamanhos e pesos:")
for animal, tamanho, peso in zip(animais, tamanhos, pesos_estimados):
print(f"O {animal} é {tamanho} e pesa aproximadamente {peso} kg.")
Comando break
O comando break encerra imediatamente o laço atual (for ou while) e transfere o controle para a instrução que segue o laço.
print("Buscando número 7:")
for numero in range(1, 11):
if numero == 7:
print(f"Encontrei o {numero}, saindo do laço!")
break
print(f"Processando: {numero}")
print("Final da busca.")
Comando continue
O comando continue interrompe a iteração atual do laço e passa para a próxima iteração. As instruções restantes no bloco do laço para a iteração atual são ignoradas.
print("Processando apenas números pares:")
for valor in range(10):
if valor % 2 != 0: # Se o número for ímpar
print(f"Pulando o {valor} (ímpar).")
continue # Pula para a próxima iteração
print(f"Processando o par: {valor}")
Um exemplo mais complexo, utilizando ambos break e continue:
senhas_permitidas = ["segredo123", "adminpass"]
tentativas_disponiveis = 3
while tentativas_disponiveis > 0:
entrada_usuario = input(f"Por favor, digite a senha (tentativas restantes: {tentativas_disponiveis}): ")
autenticado = False
for senha_armazenada in senhas_permitidas:
if entrada_usuario == senha_armazenada:
autenticado = True
break # Sai do laço 'for' interno se a senha for encontrada
if autenticado:
print("Acesso concedido! Bem-vindo.")
break # Sai do laço 'while' externo
else:
print("Senha incorreta. Por favor, tente novamente.")
tentativas_disponiveis -= 1
# O 'continue' aqui não é estritamente necessário,
# pois o laço 'while' continuaria naturalmente para a próxima iteração,
# mas poderia ser usado para pular código adicional que estivesse abaixo.
# continue
if not autenticado and tentativas_disponiveis == 0:
print("Número máximo de tentativas excedido. Acesso bloqueado por segurança.")
Comando pass
O comando pass é uma operação nula (No-Operation - NOP). Ele não faz absolutamente nada e é usado como um placeholder onde uma instrução é sintaticamente exigida, mas você não quer que nenhuma ação seja realizada ainda. É útil para criar classes ou funções vazias que serão implementadas posteriormente.
def funcao_a_implementar():
pass # A função será implementada depois
class NovoComponente:
# A classe será definida mais tarde
pass
if False:
print("Isso nunca será executado.")
else:
pass # Nenhuma ação específica para o caso 'else'
Iteradores e a Função iter()
Um iterador é um objeto que implementa o protocolo de iteração, o que significa que ele tem um método __next__() (em Python 3) que retorna o próximo item de uma sequência. Quando não há mais itens, ele levanta a exceção StopIteration. Objetos iteráveis (como listas, tuplas, strings, dicionários, arquivos) são aqueles que podem ser passados para a função iter() para obter um iterador.
Usando Iteradores
1. Sequências
Quando você usa um laço for com uma sequência, Python internamente converte a sequência em um iterador e chama __next__() (ou a função nativa next()) em cada iteração.
elementos_tupla = ("alpha", 123, 4.56)
iterador_tupla = iter(elementos_tupla)
print(next(iterador_tupla)) # Saída: alpha
print(next(iterador_tupla)) # Saída: 123
print(next(iterador_tupla)) # Saída: 4.56
# print(next(iterador_tupla)) # Chamada adicional levantaria StopIteration
2. Dicionários
Ao iterar diretamente sobre um dicionário, o iterador padrão percorre suas chaves.
estoque_loja = {'camisa': 25, 'calça': 15, 'sapato': 10}
print("Iterando sobre as chaves (padrão):")
for item_chave in estoque_loja: # Itera sobre as chaves
print(f"{item_chave}: {estoque_loja[item_chave]} unidades")
print("\nIterando sobre os valores:")
for qtd_item in estoque_loja.values():
print(f"Quantidade: {qtd_item}")
print("\nIterando sobre pares chave-valor:")
for produto, quantidade in estoque_loja.items():
print(f"Produto: {produto}, Qtd: {quantidade}")
Em Python 3, os métodos keys(), values() e items() de dicionários retornam objetos de "visualização" (view objects) que são iteráveis e se comportam de maneira eficiente, gerando itens sob demanda sem criar uma lista completa na memória.
3. Arquivos
Objetos de arquivo são seus próprios iteradores. Ao iterar diretamente sobre um objeto de arquivo, ele lerá e produzirá uma linha por vez, o que é eficiente para arquivos grendes.
# Supondo que 'documento.txt' exista e tenha algumas linhas
# with open('documento.txt', 'r', encoding='utf-8') as arquivo:
# for linha_lida in arquivo:
# print(linha_lida.strip()) # .strip() para remover caracteres de nova linha
Criando Iteradores com iter()
A função iter() pode ser usada de duas formas:
iter(objeto_iteravel): Retorna um iterador para oobjeto_iteravelfornecido.iter(funcao, sentinela): Cria um iterador que chama repetidamentefuncao. O iterador para quando o valor retornado pelafuncaoé igual àsentinela.
# Exemplo iter(funcao, sentinela)
import random
def gerar_dado():
"""Simula o lançamento de um dado de 6 faces."""
return random.randint(1, 6)
# Itera sobre os lançamentos do dado até que um 3 seja obtido
print("Lançando o dado até cair 3:")
for resultado in iter(gerar_dado, 3):
print(f"Resultado: {resultado}")
print("Um 3 foi lançado, o iterador parou.")
Compreensões de Lista (List Comprehensions)
As compreensões de lista oferecem uma forma concisa e eficiente de criar listas, aplicando uma expressão a cada item de um iterável, opcionalmente filtrando os itens. São geralmente mais legíveis e performáticas do que os laços for tradicionais para a criação de listas.
Sintaxe Básica
[expressao for variavel in iteravel]
# Criando uma lista dos cubos dos primeiros 5 números inteiros
cubos = [x ** 3 for x in range(5)]
print(f"Lista de cubos: {cubos}") # Saída: [0, 1, 8, 27, 64]
Com Condição Opcional
[expressao for variavel in iteravel if condicao]
# Filtrando apenas nomes que começam com 'A'
nomes = ["Alice", "Bob", "Ana", "Carlos"]
nomes_com_A = [nome for nome in nomes if nome.startswith('A')]
print(f"Nomes que começam com 'A': {nomes_com_A}") # Saída: ['Alice', 'Ana']
Compreensões Aninhadas (Matrizes)
Podem ser usadas para criar listas de listas ou representar estruturas como matrizes, usando múltiplos laços for.
# Criando uma matriz 2x3 de coordenadas (linha, coluna)
# As linhas vão de 0 a 1, colunas de 0 a 2
matriz_2x3 = [(linha, coluna) for linha in range(2) for coluna in range(3)]
print(f"Coordenadas da matriz 2x3: {matriz_2x3}")
# Saída: [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
Expressões Geradoras (Generator Expressions)
As expressões geradoras são uma extensão das compreensões de lista. A principal diferença é que elas retornam um objeto gerador, em vez de criar e retornar uma lista completa em memória. Este objeto produz valores "sob demanda", ou seja, um por vez, economizando memória, especialmente para grandes conjuntos de dados ou quando nem todos os resultados são necessários imediatamente.
Sintaxe
(expressao for variavel in iteravel if condicao_opcional)
# Exemplo: Soma dos quadrados de números ímpares (gerador para economia de memória)
soma_quadrados_impares = sum(x**2 for x in range(1, 10) if x % 2 != 0)
print(f"Soma dos quadrados dos ímpares de 1 a 9: {soma_quadrados_impares}") # Saída: 1+9+25+49+81 = 165
Exemplo de Produto Cartesiano
Combinando iteráveis para gerar pares de forma eficiente com um gerador.
eixos_X = [1, 2, 3]
def gerar_eixos_Y():
"""Simula um gerador de valores para o eixo Y."""
yield 'A'
yield 'B'
yield 'C'
# Cria um gerador de tuplas (x, y)
pontos_cartesianos = ((x, y) for x in eixos_X for y in gerar_eixos_Y())
print("Gerando pontos cartesianos:")
for ponto in pontos_cartesianos:
print(ponto)
Otimizando Leitura de Arquivos
Usar expressões geradoras pode simplificar e otimizar a leitura e processamento de arquivos grandes, evitando carregar o arquivo inteiro na memória.
import os
# Criar um arquivo de teste temporário para o exemplo
temp_file_path = 'dados_exemplo.txt'
with open(temp_file_path, 'w', encoding='utf-8') as f:
f.write("Primeira linha.\n")
f.write("Esta é uma linha um pouco mais longa.\n")
f.write("Curta.\n")
f.write("A linha mais longa de todas, com muitos caracteres.\n")
f.write("Última linha do arquivo.\n")
def encontrar_maior_comprimento_linha(caminho_arquivo):
"""Retorna o comprimento da linha mais longa em um arquivo."""
with open(caminho_arquivo, 'r', encoding='utf-8') as arquivo:
# A expressão geradora processa cada linha uma por vez,
# calculando seu comprimento após remover espaços e quebras de linha,
# sem carregar todas as linhas na memória ao mesmo tempo.
comprimentos_linhas = (len(linha.strip()) for linha in arquivo)
return max(comprimentos_linhas)
maior_len = encontrar_maior_comprimento_linha(temp_file_path)
print(f"O comprimento da linha mais longa é: {maior_len} caracteres.")
# Limpar o arquivo de teste
os.remove(temp_file_path)