Pular para o conteúdo

    Capítulo 32, Intermediário

    Comprehensions

    Uma compreensão transforma um laço de quatro linhas em uma expressão. Usada com bom senso, deixa o código mais claro. Usada em excesso, o torna ilegível.

    Código deste capítulo: intermediario/cap32_comprehensions.py

    Listas, conjuntos e dicionários

    A forma geral é [expressão for item in iterável if condição]. O mesmo vale para chaves {}, que criam conjuntos e dicionários:

    intermediario/cap32_comprehensions.pylinhas 10 a 18
    quadrados = [n ** 2 for n in range(6)]
    pares = [n for n in range(10) if n % 2 == 0]
    print(quadrados)
    print(pares)
    
    palavras = ["python", "go", "rust"]
    tamanhos = {p: len(p) for p in palavras}
    unicos = {len(p) for p in palavras}
    print(tamanhos, sorted(unicos))
    
    Saída
    [0, 1, 4, 9, 16, 25]
    [0, 2, 4, 6, 8]
    {'python': 6, 'go': 2, 'rust': 4} [2, 4, 6]
    

    Quando a transformação tem uma escolha, a expressão condicional vai antes do for. O if do final só filtra:

    intermediario/cap32_comprehensions.pylinhas 20 a 21
    rotulos = ["par" if n % 2 == 0 else "ímpar" for n in range(4)]
    print(rotulos)
    
    Saída
    ['par', 'ímpar', 'par', 'ímpar']
    

    Compreensões aninhadas

    Dois for na mesma compreensão percorrem as duas dimensões, do externo para o interno, na mesma ordem em que você escreveria os laços:

    intermediario/cap32_comprehensions.pylinhas 26 a 30
    matriz = [[1, 2, 3], [4, 5, 6]]
    achatada = [n for linha in matriz for n in linha]
    transposta = [[linha[i] for linha in matriz] for i in range(3)]
    print(achatada)
    print(transposta)
    
    Saída
    [1, 2, 3, 4, 5, 6]
    [[1, 4], [2, 5], [3, 6]]
    

    Expressões geradoras

    Trocando os colchetes por parênteses, você obtém uma expressão geradora, que não monta a lista na memória e produz um item de cada vez. Dentro de uma chamada como sum, os parênteses extras são opcionais:

    intermediario/cap32_comprehensions.pylinhas 35 a 39
    soma = sum(n ** 2 for n in range(1000))
    print(soma)
    
    nomes = ["Ana", "Bia", "Caio"]
    print(any(len(n) > 3 for n in nomes), all(n[0].isupper() for n in nomes))
    
    Saída
    332833500
    True True
    

    Funções como sum, any, all, min e max consomem geradores, e any e all param assim que o resultado está decidido.

    O limite da legibilidade

    Minha regra: uma compreensão com mais de um for ou com mais de uma condição já merece virar um laço comum ou uma função com nome. Se eu preciso reler duas vezes para entender, o próximo leitor também precisará.

    Exercício 1

    Transpor uma matriz

    Escreva transpor(matriz) com uma compreensão. Dica: zip(*matriz).

    Exercício 2

    Inverter chaves e valores

    Escreva inverter(d) que troque chaves e valores de um dicionário.