2.11. Condicionais

Um condicional executa um bloco de código apenas quando algum teste avalia como verdadeiro. A palavra-chave é if, opcionalmente seguida por um ou mais ramos elif (“else if”) e um else final.

n = 42

if n > 0:
    print("positive")
elif n < 0:
    print("negative")
else:
    print("zero")

O corpo de cada ramo é tudo o que está indentado sob ele (quatro espaços por convenção). O Python percorre os ramos em ordem, executa o primeiro cujo teste é verdadeiro e ignora o resto. O bloco else é executado somente se todos os testes anteriores foram falsos; ele é sempre opcional.

Um fluxograma mostrando if/elif/else: dois losangos de decisão com seus corpos, caindo para um corpo else final quando ambos os testes são falsos.

Apenas um ramo é executado. Os testes são avaliados de cima para baixo até que um tenha sucesso; o resto é ignorado.

2.11.1. Veracidade (truthiness)

Um teste em um if não precisa retornar True ou False – qualquer valor conta como truthy (verdadeiro) ou falsy (falso). Os valores falsy são:

  • False e None

  • O número zero: 0, 0.0

  • Sequências e coleções vazias: "", [], (), {}, b""

Todo o resto é truthy. Isso permite escrever testes compactos:

if name:                     # false on empty string
    print("hello", name)

if items:                    # false on empty list, dict, etc.
    process(items)

Esteja ciente de que a veracidade muda o significado. if value: não é o mesmo que if value is not None: – o primeiro também é falso quando value é 0 ou "". Quando você realmente quer dizer “isto é exatamente None“, use is None / is not None explicitamente.

2.11.2. Expressões ternárias

Um condicional pode aparecer dentro de uma expressão:

label = "even" if n % 2 == 0 else "odd"

Leia como “label é "even" se n % 2 == 0 senão "odd".” Útil para one-liners; para qualquer coisa com mais de uma linha, uma instrução if completa é mais fácil de ler.

2.11.3. Aninhamento e retornos antecipados

Os condicionais podem ser aninhados arbitrariamente fundo, mas cada camada extra de indentação torna uma função mais difícil de ler. O exemplo abaixo verifica quatro condições antes de fazer o trabalho real e deixa a linha útil enterrada quatro indentações dentro:

def process(item):
    if item is not None:
        if item.is_valid():
            if item.size() > 0:
                if item.owner == "me":
                    return do_the_work(item)
    return None

Dois padrões achatam esse tipo de código.

2.11.3.1. Retornos antecipados para guardas

Trate primeiro cada caso de “desistir”, cada um com seu próprio return, para que a lógica principal permaneça na indentação externa. Cada guarda lê-se como “este não é um caso que tratamos; saia”:

def process(item):
    if item is None:
        return None
    if not item.is_valid():
        return None
    if item.size() == 0:
        return None
    if item.owner != "me":
        return None
    return do_the_work(item)

O “caminho principal” agora é uma única linha no fim da função, não enterrado dentro de quatro camadas. Esse estilo é às vezes chamado de padrão de cláusula de guarda.

2.11.3.2. Combinando testes com and / or

Quando várias condições precisam todas valer para o mesmo ramo, combine-as com and em vez de aninhar. Condições que cada uma independentemente aciona o ramo combinam-se com or:

# all must hold -- use `and`
if user.is_admin() and user.has_permission("write") and not locked:
    save()

# any one of them is enough -- use `or`
if c == " " or c == "\t" or c == "\n":
    whitespace_count += 1

Ambas as formas têm curto-circuito, então uma verificação custosa do lado direito só é executada quando as verificações mais baratas à esquerda ainda não resolveram a questão.