2.13. Controlo de ciclos

Duas palavras-chave alteram o funcionamento de um ciclo:

  • break – sai do ciclo imediatamente.

  • continue – salta o resto da iteração atual e inicia a próxima.

Ambas se aplicam ao ciclo mais interior em que aparecem.

2.13.1. break

Use break para parar um ciclo assim que uma condição for satisfeita. O padrão clássico de «procurar e parar»:

found = None
for item in items:
    if matches(item):
        found = item
        break

if found is not None:
    print("found:", found)

Num ciclo while True:, o break é a forma de terminar o ciclo:

while True:
    line = next_line()
    if line == "quit":
        break
    process(line)

2.13.2. continue

Use continue para saltar o resto do corpo e passar para a próxima iteração. Útil para filtrar itens dentro de um ciclo:

for n in numbers:
    if n < 0:
        continue            # skip negatives
    print(n)

O mesmo efeito pode ser escrito como um bloco if em torno do resto do corpo. O continue é por vezes mais claro quando a condição de salto é mais fácil de enunciar do que a condição de manter.

Dentro de um ciclo, o continue desempenha o mesmo papel que um return antecipado numa função: saltar os casos que não se tratam e manter o trabalho principal nivelado no recuo exterior. O ciclo filtrar-e-processar é a forma canónica:

for item in items:
    if item is None:
        continue
    if not item.is_valid():
        continue
    process(item)

A linha process(item) com recuo é o trabalho efetivo; cada guarda acima especifica exatamente quais os itens que são ignorados.

2.13.3. else num ciclo

Tanto o for como o while aceitam um bloco else opcional. Este é executado quando o ciclo termina sem atingir um break. O uso mais comum é um ciclo de pesquisa que precisa de um valor de substituição caso nada seja encontrado:

for item in items:
    if matches(item):
        print("found:", item)
        break
else:
    print("no match")

Se um break for ativado, o bloco else é ignorado. Leia a construção como «for X in Y: …; caso contrário, se nunca saímos com break, faz Z.»

2.13.4. Padrões comuns de ciclos

Alguns padrões aparecem frequentemente em scripts reais:

  • Polling – aguardar que uma condição se torne verdadeira antes de continuar. O corpo utiliza pass, a instrução de não-operação do Python; cada bloco com recuo deve conter pelo menos uma instrução, e pass é a forma de dizer «não fazer nada aqui»:

    while not ready():
        pass
    proceed()
    
  • Máquina de estados – um único ciclo while True: que decide o que fazer com base numa variável de estado. Útil quando o trabalho se divide claramente em algumas fases com nome:

    state = "header"
    for line in lines:
        if state == "header":
            if line.startswith("---"):
                state = "body"
        elif state == "body":
            print(line)
    
  • Acumulação – construir um resultado enquanto se percorre uma sequência:

    total = 0
    for x in samples:
        total += x
    mean = total / len(samples)
    

    Muitos ciclos de acumulação têm um equivalente de uma linha usando uma função incorporada. Recorra à função incorporada quando uma se aplica:

    • sum() – soma todos os itens de um iterável.

    • max() / min() – o maior ou menor item.

    • any()True se pelo menos um item for verdadeiro.

    • all()True apenas quando todos os itens são verdadeiros.

    • sorted() – uma nova lista com os itens ordenados.

    • len() – o número de itens (quando o iterável conhece o seu comprimento).

    >>> samples = [3, 1, 4, 1, 5, 9, 2, 6]
    >>> sum(samples)
    31
    >>> sum(samples) / len(samples)        # mean
    3.875
    >>> max(samples)
    9
    >>> min(samples)
    1
    >>> sorted(samples)
    [1, 1, 2, 3, 4, 5, 6, 9]
    >>> any([False, False, True])
    True
    >>> all([True, True, False])
    False
    

    A versão com função incorporada é mais curta, mais clara e geralmente mais rápida do que escrever o mesmo ciclo manualmente.