Dev (Back & Front)ARTIGO

Explicando comprehensions para programadores

No primeiro ou no segundo ano programando com PythonPython56 conteúdosVSCode + Python + Alexa: Desenvolva e teste skills para alexa localmente com pythonDev (Back & Front) · out 2025Dominando decoradores em Python: um guia completo com exemplosDev (Back & Front) · jan 2025Desenvolvimento de software: diferenças entre Python, JavaScript e JavaGestão Dev & TI · nov 2024Ver tudo em Dev (Back & Front) , eu nunca usei list comprehension (na época, eram comprehensions apenas). Eu li sobre elas, meio que descobri como trabalhavam, e depois agarrei map() e filter(), os quais eu entendi. Olhando para trás, acho que isso tem muito a ver com o fato de que as explicações de comprehensions são feitas usando a sua origem – a matemática – em vez do domínio em que as usamos – programação.

Uma busca rápida no DuckDuckGo me diz que esse ainda é o caso – a Wikipedia nos pede para considerar algo como isto: S = {2 ? x | x?N | x> 3}, e outras fontes também parecem começar com ‘isso é como é feito em matemática, então … ‘ (uma exceção notável é o tutorial sobre python.org).

Ao falar com programadores, eu gostaria de explicar comprehensions de maneira diferente, porque nem todos eles têm um background em matemática. Para um programador, uma list comprehension é simplesmente um loop de for´s para constrir listas, usando uma notação mais declarativa do que um loop for usual. Para aqueles de nós que acostumados a map() e filter(), list comprehension são as duas coisas também.

Considere o seguinte:

def loop(my_list):
result = []
for x in my_list:
if x > 3:
result.append(x*2)
return result

Já escreveu alguma vez um código como esse? Esse é o código que afirma explicitamente que medidas devem ser tomadas para a construção de sua lista; mas você não precisa – em vez disso, você pode indicar o que você deseja:

def compr(my_list):
return [x*2 for x in my_list if x > 3]

Isso se traduz para me dar valor*2 para cada valor em my_list, mas apenas se esse valor for superior a três. Note também que essa expressão funciona com map (multiplipar por dois) e filter (usar apenas os valores que são menores de dois). O normal seria [acrescentar algo à lista for para cada valor em um iterável, opcionalmente apenas se uma condição if for True para aquele valor].

Comprehensions também funcionam aninhadas – considere este código simples, mas feio:

def create_matrix_loop(size, default):
new_matrix = []
for y in range(size):
row = []
for x in range(size):
row.append(default)
new_matrix.append(row)
return new_matrix

Exemplo de saída:

>create_matrix_loop(3, None)
[[None, None, None],
[None, None, None],
[None, None, None]]

Uma vez que comprehensions podem ser aninhadas, isso pode ser substituído por:

def create_matrix_compr(size, default):
return [[default for x in range(size)] for x in range(size)]

Como um bônus adicional, quando não dizemos ao compilador como queremos fazer algo, mas sim o que nós queremos que seja feito, pode gerar um melhor – mais rápido – bytecode para nós. A versão loop de create_matrix está traduzida em 35 instruções de bytecode, e a versão usando uma list comprehension é apenas 20 (tente import dis; dis.dis (func) para ver como func aparece em bytecode) e, na realidade, muitas vezes você vai evitar fazer uma função ao usar comprehensions, uma vez que elas são concisas o suficiente, fazendo essa diferença ainda maior. Ao cronometrar as implementações, a diferença é evidente:

>timeit -n100 create_matrix_loop(1000, None)
100 loops, best of 3: 113 ms per loop
>timeit -n100 create_matrix_compr(1000, None)
100 loops, best of 3: 49.1 ms per loop

É isso mesmo: menos código, sintaxe declarativa, e uma execução mais rápida! (Nota: Eu usei o iPython ao criar e cronometrar os exemplos – é impressionante e você deve experimentá-lo)

?

Texto original disponível em http://blaag.haard.se/Explaining-comprehensions-to-programmers/

É programador, desenvolvedor, consultor e, ocasionalmente, professor e palestrante.

Ver perfil