Skip to content

    Chapter 32, Intermediate

    Comprehensions

    A comprehension transforms a four-line loop into an expression. Used sensibly, it makes the code clearer. Used excessively, it makes it unreadable.

    Code for this chapter: intermediario/cap32_comprehensions.py

    Lists, sets, and dictionaries

    The general form is [expressão for item in iterável if condição]. The same applies to braces {}, which create sets and dictionaries:

    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))
    
    Output
    [0, 1, 4, 9, 16, 25]
    [0, 2, 4, 6, 8]
    {'python': 6, 'go': 2, 'rust': 4} [2, 4, 6]
    

    When the transformation has a choice, the conditional expression goes before of the for. The if the end only filters:

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

    Nested comprehensions

    Two for in the same comprehension traverse both dimensions, from the outer to the inner, in the same order you would write the loops:

    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)
    
    Output
    [1, 2, 3, 4, 5, 6]
    [[1, 4], [2, 5], [3, 6]]
    

    Generator expressions

    By replacing the brackets with parentheses, you get a generator expression, which does not build the list in memory and produces one item at a time. Within a call like sum, the extra parentheses are optional:

    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))
    
    Output
    332833500
    True True
    

    Functions like sum, any, all, min and max consume generators, and any and all stop as soon as the result is determined.

    The limit of readability

    My rule: a comprehension with more than one for or with more than one condition already deserves to become a common loop or a named function. If I need to reread it twice to understand, the next reader will also need to.

    Exercise 1

    Transpose a matrix

    Write transpor(matriz) with a comprehension. Tip: zip(*matriz).

    Exercise 2

    Invert keys and values

    Write inverter(d) that swaps keys and values of a dictionary.