Oi Caio,
uma list comprehension funciona como um bloco for só que voltada para gerar uma lista.
Essa expression nada mais é que qualquer comando que vc quiser, podendo ser um valor qualquer, resultado de uma função ou mesmo uma função.
Se vc quiser pensar na estrutura, ela nada mais é do que um for colocado em uma linha.
# list comprehension
newlist = [expression for item in iterable if condition == True]
# for
newlist = []
for item in iterable:
if condition == True:
newlist.append(expression)
Como vc pode ver, a expressão é apenas um comando que vc quer realizar, normalmente com o item numa lista comprehension, mas não obrigatoriamente.
palavra = 'programa'
# gera uma lista com cada uma das letras separadas
l1 = [letra for letra in palavra]
# gera uma lista com cada uma das letras separadas e maiusculas
l2 = [letra.upper() for letra in palavra]
# gera uma lista com o mesmo valor sempre
l3 = [1 for letra in palavra]
# gera uma lista com cada letra repetida
l4 = [letra+letra for letra in palavra]
# gera lista a partir de um range
l5 = [i for i in range(10)]
# gera lista com valores ao quadrado a partir de um range
l6 = [i**2 for i in range(10)]
Esses são alguns exemplos que talvez ajudem a entender melhor.