Controle de fluxo
Todo programa que você escreveu até agora executa do mesmo jeito toda vez: de cima para baixo, uma linha de cada vez. Isso funciona para scripts simples, mas programas reais precisam tomar decisões e repetir trabalho. Um quiz precisa checar se a resposta está certa. Um jogo precisa continuar rodando até o jogador vencer ou perder. Este capítulo mostra como fazer seu programa se ramificar e repetir.
Comparações
Antes de poder tomar uma decisão, você precisa comparar coisas. Operadores de comparação retornam True ou False. O mais importante acertar cedo: = atribui um valor, == verifica se dois valores são iguais. Misturar os dois é um dos erros mais comuns entre iniciantes.
5 > 3 # True
5 < 3 # False
5 == 5 # True (note: dois iguais; = é atribuição, == é comparação)
5 != 3 # True ("não é igual a")
5 >= 5 # True ("maior ou igual a")
5 <= 4 # False ("menor ou igual a")A distinção entre = e == confunde quase todo mundo no começo. Atribuição (=) armazena um valor; comparação (==) verifica se dois valores são iguais.
Você também pode comparar strings. Python as compara alfabeticamente, caractere por caractere, coisa que o capítulo Strings cobre em mais detalhe:
"apple" == "apple" # True
"apple" < "banana" # True (a vem antes de b)
"apple" == "Apple" # False (sensível a maiúsculas)= armazena um valor, == verifica se dois valores são iguais. Eu ainda desacelero e confiro bem esse quando estou cansado, então você está em boa companhia se isso te confundir. Comparações devolvem True ou False, e funcionam em strings também, alfabeticamente. Combinando condições
and, or e not combinam comparações. and exige que ambos os lados sejam verdadeiros. or exige que pelo menos um lado seja. not inverte o resultado. Esses permitem expressar condições do mundo real como "pontuação está passando E usuário está ativo".
age = 25
score = 88
age >= 18 and score >= 80 # True (ambos devem ser verdadeiros)
age < 18 or score >= 80 # True (pelo menos um deve ser verdadeiro)
not age >= 18 # False (inverte o resultado)and exige ambos os lados. or exige pelo menos um lado. not inverte.
and quer ambos os lados verdadeiros, or quer pelo menos um, not inverte a resposta. Isso cobre a maioria das condições reais que você vai escrever, como "pontuação está passando and o usuário está ativo". Python para de checar no momento em que sabe o resultado. Truthy e falsy
Todo valor em Python tem uma interpretação booleana, mesmo se não for True ou False. Strings vazias, zero, listas vazias e None se comportam como False em uma condição. Tudo mais se comporta como True. Isso significa if results: verifica se uma lista não está vazia sem escrever if len(results) > 0:.
# Tudo isso se comporta como False em uma condição:
False, 0, 0.0, "", [], {}, (), None
# Tudo mais se comporta como TrueIsso significa if results: é um jeito natural de dizer "se a lista não está vazia", e if name: verifica se uma string tem algum conteúdo.
False em uma condição: 0, "", [] e None. Tudo mais conta como True. É por isso que if results: lê tão limpo como "se há algo na lista", nenhum len() necessário. if / elif / else
A declaração if roda um bloco de código apenas quando sua condição é True. elif adiciona mais condições para checar se a primeira foi falsa. else captura tudo que não correspondeu a nenhuma condição. Python usa indentação, não chaves, para definir o que pertence dentro de cada bloco.
score = 87
if score >= 90:
print("Nota A")
elif score >= 80:
print("Nota B")
elif score >= 70:
print("Nota C")
else:
print("Abaixo de C")As regras:
ifé obrigatório e sempre vem primeiroelif(abreviação de "else if") é opcional e você pode ter quantos precisarelseé opcional, lida com tudo que não correspondeu, e vem por último- Python usa indentação (4 espaços) para marcar o que pertence dentro de cada bloco; não há chaves
A indentação não é opcional ou cosmética. Python a usa para definir estrutura. Indentação inconsistente é um erro de sintaxe.
if roda seu bloco quando a condição é verdadeira, elif verifica mais casos, else captura o resto. Apenas o primeiro que bate roda. A coisa que me pegou cedo: indentação é o que diz ao Python onde cada bloco começa e termina, então mantenha consistente. Condições em uma linha
Para atribuições simples sim/não, Python tem uma forma compacta de uma linha chamada expressão ternária: value_if_true if condition else value_if_false. Use apenas quando a lógica for pequena e ler como uma sentença.
label = "passou" if score >= 50 else "falhou"Essa é uma expressão ternária; lê como uma sentença. Use quando a lógica for pequena. Para qualquer coisa envolvendo elif, escreva a versão completa.
value_if_true if condition else value_if_false escolhe um de dois valores em uma linha. É lindo para escolhas arrumadas e pequenas como "passou" if score >= 50 else "falhou". No momento que a lógica cresce além disso, volta para um bloco if normal, vai ler melhor. Loops while
Um loop while repete seu bloco enquanto sua condição é True. Use quando você não sabe com antecedência quantas vezes o loop deve rodar, por exemplo esperando entrada válida ou tentando novamente até um trabalho conseguir.
lives = 3
while lives > 0:
print(f"Vidas restantes: {lives}")
lives -= 1
print("Game over")while é melhor quando você não sabe com antecedência quantas vezes o loop vai rodar. Quando você sabe, ou quando está iterando uma coleção, for é mais limpo.
while continua rodando seu bloco enquanto a condição fica verdadeira. Use quando você não sabe quantas rodadas vai precisar, como esperando entrada válida. Certifique-se de que algo dentro do loop se move na direção da saída, ou vai rodar para sempre, um erro que eu cometi mais de uma vez. break e continue
break sai do loop imediatamente, não importa quantas iterações restam. continue pula o resto da iteração atual e volta para a verificação de condição. Ambas apenas afetam o loop mais próximo que elas estão.
break sai do loop imediatamente:
target = 5
num = 0
while True:
num += 1
if num == target:
print(f"Encontrado {target}")
break # para o loopwhile True: com um break é um padrão válido e comum quando a condição de saída é complexa ou precisa acontecer no final do corpo do loop.
continue pula o resto da iteração atual e volta para a verificação de condição:
num = 0
while num < 10:
num += 1
if num % 2 == 0:
continue # pula números pares
print(num) # apenas números ímpares imprimem: 1, 3, 5, 7, 9break salta para fora do loop na hora, continue pula o resto dessa rodada e volta a checar a condição. Ambas apenas tocam o loop que elas estão diretamente dentro. while True: com um break lê estranho no começo, mas é um jeito normal de fazer um loop até algo acontecer. Loops for
Um loop for passa por uma sequência um item de cada vez: uma lista, uma string, um intervalo de números. A variável que você nomeia depois de for recebe cada item por vez. Você não gerencia um contador ou verifica o comprimento você mesmo.
players = ["Alice", "Bob", "Charlie"]
for player in players:
print(f"Olá, {player}!")Loops for também funcionam em strings (iterando caractere por caractere) e em qualquer outro tipo de sequência.
for item in sequence anda cada item por vez, e você nunca toca um contador ou um comprimento você mesmo. Funciona em listas, strings, intervalos, muitas coisas. Vindo de outras linguagens, não gerenciar o índice pareceu estranho para mim no começo, depois pareceu um presente. range()
range() gera uma sequência de números para você fazer loop. range(5) te dá 0, 1, 2, 3, 4. Você pode controlar o começo, fim e tamanho do passo. Use quando você precisar de um loop rodar um número específico de vezes.
for i in range(5):
print(i) # 0, 1, 2, 3, 4range() tem três formas:
| Chamada | O que produz |
|---|---|
range(5) | 0, 1, 2, 3, 4 |
range(2, 6) | 2, 3, 4, 5 |
range(0, 10, 2) | 0, 2, 4, 6, 8 (passo de 2) |
range(5, 0, -1) | 5, 4, 3, 2, 1 (contagem para baixo) |
range() não cria uma lista. Produz números um de cada vez, o que é eficiente mesmo para intervalos muito grandes.
range(5) te dá 0, 1, 2, 3, 4, e você pode configurar um começo, fim e passo. Use quando você quer um loop rodar um número configurado de vezes. Não constrói uma lista, te entrega um número por rodada. enumerate()
enumerate() te dá tanto o índice quanto o valor enquanto você faz loop, então você não precisa rastrear um contador separadamente. A parte i, player automaticamente recebe um par de valores em cada iteração.
players = ["Alice", "Bob", "Charlie"]
for i, player in enumerate(players):
print(f"{i + 1}. {player}")
# 1. Alice
# 2. Bob
# 3. CharlieA sintaxe i, player é chamada unpacking. Python divide o par (index, value) em dois nomes automaticamente.
Por padrão enumerate() começa em 0. Passe um valor inicial para mudar:
for i, player in enumerate(players, start=1):
print(f"{i}. {player}") # começa em 1enumerate() te entrega a posição e o valor juntos, então nenhum contador separado para manter em sincronia. A parte i, player pega ambos de uma vez. Passe start=1 quando você está numerando uma lista para alguém ler. Loops aninhados
Você pode colocar um loop dentro de outro loop. O loop interior roda completamente para cada iteração única do loop exterior. Esse é o jeito de processar grids, combinações ou qualquer dado com dois níveis de estrutura.
rows = [1, 2, 3]
cols = ["A", "B"]
for row in rows:
for col in cols:
print(f"{col}{row}", end=" ")
print() # nova linha depois de cada linha
# A1 B1
# A2 B2
# A3 B3break e continue dentro de um loop aninhado apenas afetam o loop mais próximo.
break e continue apenas agem no loop que ficam, o interior aqui. Loop-else
Loops do Python podem ter uma cláusula else que roda apenas se o loop terminou sem bater um break. Não é comum, mas é o jeito mais limpo de escrever "procure uma lista, e se nada for encontrado, faça isso".
target = "Dave"
names = ["Alice", "Bob", "Charlie"]
for name in names:
if name == target:
print(f"Encontrado {target}")
break
else:
print(f"{target} não está na lista") # roda porque break nunca disparouSe break roda, o else é pulado. Se o loop esgota a sequência, else roda. É um padrão de nicho mas mais limpo que uma variável flag.
else que roda apenas quando o loop termina sem um break. Não é usado frequentemente, mas é o jeito mais arrumado de dizer "procure essa lista, e se nada corresponder, faça isso". O nome é um pouco enganoso, então um comentário breve ajuda. Ordenação
sorted() retorna uma nova lista ordenada e deixa a original inalterada. .sort() ordena a lista no lugar e retorna None. O argumento key= permite você ordenar por algo diferente do valor bruto. Por exemplo, ordenar nomes insensitivamente a maiúsculas ou ordenar tuplas de jogador por sua pontuação.
scores = [87, 42, 96, 55, 71]
ranked = sorted(scores) # [42, 55, 71, 87, 96] (nova lista)
scores.sort() # ordena a lista original, retorna None
scores.sort(reverse=True) # [96, 87, 71, 55, 42]Ambas aceitam um argumento key=: uma função aplicada a cada item antes da comparação:
names = ["Charlie", "Alice", "Bob"]
sorted(names, key=str.lower) # ordenação insensitiva a maiúsculas
players = [("Alice", 87), ("Bob", 96), ("Charlie", 55)]
sorted(players, key=lambda p: p[1]) # ordena por pontuaçãolambda p: p[1] é uma função de uma linha: toma uma tupla de jogador e retorna a pontuação. Lambdas recebem tratamento completo no capítulo Lambdas e compreensões.
Para casos simples, use sorted(). Para listas onde você quer modificar no lugar, use .sort().
sorted() entrega de volta uma nova lista ordenada e deixa a original sozinha, .sort() rearranja a lista ela mesma e retorna None. Passe key= para ordenar por algo diferente do valor bruto, como nomes insensitivamente a maiúsculas. Quando em dúvida, use sorted(), é a segura. Na prática
Faça loop através de pontuações, acumule um total, conte notas que passaram e imprima um resumo:
raw_scores = [87, 42, 96, 55, 71, 63]
total = 0
passing = 0
for score in raw_scores:
total += score
if score >= 60:
passing += 1
average = total / len(raw_scores)
print(f"Média: {average:.1f}")
print(f"Passando: {passing}/{len(raw_scores)}")
print(f"Pontuação máxima: {sorted(raw_scores, reverse=True)[0]}")
