Compreensões e geradores
Transformações e filtros em compreensões, percursos aninhados e consumo de iteradores.
Compreensões
[expressao for x in xs if condicao] percorre, filtra e transforma os valores aceites, construindo uma lista nova.
xs = [-2, 0, 3, 4]
print([x * x for x in xs if x > 0]) # [9, 16]
print(["par" if x % 2 == 0 else "ímpar" for x in range(4)])
# ['par', 'ímpar', 'par', 'ímpar']
- O
iffinal filtra entradas;a if condicao else bescolhe um resultado por entrada e não reduz o número de posições. - Os
forseguem a ordem dos ciclos:[x for linha in matriz for x in linha]percorre cada linha e os seus valores. Aplana apenas um nível. {expressao for x in xs}cria um conjunto sem repetidos;{chave: valor for x in xs}cria um dicionário, conservando o último valor para cada chave repetida.- Criar uma lista exterior nova não impede efeitos:
[linha.append(9) for linha in xs]altera as linhas e produz valoresNone. Usa um ciclo para efeitos; uma compreensão para calcular resultados.
Pares e intervalos
for i in range(n)seguido defor j in range(i + 1, n)visita cada par de posições uma vez, sem pares de uma posição consigo própria.- Reservas semiabertas e , com
a < bec < d, conflituam quandomax(a, c) < min(b, d). Se apenas se tocam no extremo, não há conflito. Intervalos fechados exigem outra condição.
Iteráveis e iteradores
- Um iterável permite obter um percurso; listas e strings são exemplos.
- Um iterador conserva a posição desse percurso:
iter(xs)cria-o,next(it)pede o próximo valor. - Ao esgotar, lança
StopIteration, quefortrata para terminar. - Uma lista permite novos percursos; um iterador esgotado não reinicia.
map,filtere geradores consomem-se desta forma.
Geradores e yield
Uma expressão (expressao for x in xs) cria um gerador, que produz os resultados a pedido em vez de guardar logo uma lista.
def contagem(n):
while n > 0:
yield n
n -= 1
g = contagem(3)
print(next(g))
print(list(g))
print(list(g))Executa o código para ver a saída e os gráficos.
A saída é 3, [2, 1] e [].
- Chamar
contagem(3)cria o gerador; o corpo começa no primeiro pedido. yieldentrega um valor e suspende, conservando nomes e ponto de execução; o pedido seguinte retoma comn -= 1.returntermina, sem produzir outro valor.
Para gerar intervalos inteiros inclusivos:
- Percorre cada
(inicio, fim)comrange(inicio, fim + 1)e usayield valor. - Exige
inicio <= fim; conserva a ordem e as repetições da entrada. - Uma lista de intervalos vazia não produz valores; um intervalo de um só valor produz-o uma vez.
Lista ou gerador
| Necessidade | Escolha |
|---|---|
| Índices ou vários percursos sem recalcular | Lista com resultados guardados |
| Consumir uma vez, valor a valor | Gerador, evitando a lista intermédia |
sum(x * x for x in range(4)) dá 14.
- Se guardares esse gerador, a segunda soma dá zero porque já foi consumido; criar outro repete o cálculo.
- Produção adiada pode reduzir memória, mas não elimina o trabalho de transformar todos os valores consumidos.