Programação funcional
Funções livres de efeitos, ordem superior, lambda, closures, map, filter e reduce.
Pureza e ordem superior
- Uma função pura devolve o mesmo resultado para os mesmos argumentos e não tem efeitos observáveis fora do cálculo. Entrada, impressão, hora, mutação dos argumentos e alterações globais quebram esse contrato.
- Alterar um acumulador local não prova um efeito no chamador. Um requisito sem atribuições nem mutação é mais restrito do que pureza.
- Funções são valores:
quadradopassa a função;quadrado(3)passa o resultado. Uma função de ordem superior recebe ou devolve funções. lambda x: x * xcria uma função de uma expressão. Um predicado decide se um valor satisfaz uma condição.
Para ordenar (nome, nota) por nota decrescente e nome crescente:
sorted(alunos, key=lambda aluno: (-aluno[1], aluno[0]))
sorted devolve outra lista e é estável: chaves iguais conservam a ordem relativa original.
Map, filter e reduce
| Operação | Regra |
|---|---|
filter(p, xs) | Conserva entradas em que p dá um valor verdadeiro |
map(f, xs) | Transforma cada entrada com f |
reduce(f, xs, z) | Acumula da esquerda para a direita, começando em z |
from functools import reduce
xs = [1, 2, 3, 4, 5]
impares = filter(lambda x: x % 2 != 0, xs)
quadrados = map(lambda x: x * x, impares)
print(reduce(lambda a, x: a + x, quadrados, 0))
print(xs)Executa o código para ver a saída e os gráficos.
A seleção dá 1, 3, 5; a transformação dá 1, 9, 25; o acumulador passa por 0, 1, 10, 35.
-
A saída é
35e a lista original fica intacta. -
Em Python 3,
mapefilterdevolvem iteradores. Consumirlist(impares)antes da redução esgota o filtro. -
Com inicial
ze entradasa, b, a redução calculaf(f(z, a), b). A ordem importa:(10 - 2) - 3dá 5. -
A entrada vazia devolve o inicial. Sem inicial, o primeiro elemento inicia o acumulador e o vazio lança
TypeError. Para somar,sumé uma alternativa direta. -
Filtrar positivos antes de elevar ao quadrado rejeita negativos; fazê-lo depois aceita os seus quadrados positivos.
Any e all
anyprocura um valor verdadeiro eallprocura um falso para decidir. Param nesse primeiro testemunho ou contraexemplo.any([])éFalse;all([])éTrue.all(any(peca in caixa for caixa in caixas) for peca in pedidas)exige que cada peça exista em alguma caixa, podendo ser diferente.any(all(peca in caixa for peca in pedidas) for caixa in caixas)exige uma caixa com todas as peças.- No primeiro contrato, sem peças pedidas o resultado é verdadeiro; com peças e sem caixas é falso. Os percursos interiores precisam de uma coleção reutilizável, não de um único iterador que esgote.
Closures e composição
def multiplicador(fator):
return lambda x: fator * x
print(multiplicador(2)(5)) # 10
- A closure conserva acesso ao contexto léxico onde foi criada.
- Não copia automaticamente valores:
[lambda x: fator * x for fator in range(1, 4)]consulta o mesmofatore, depois do percurso, todas multiplicam por 3. [multiplicador(fator) for fator in range(1, 4)]cria contextos distintos.
Compor f e g significa calcular f(g(x)).
- O resultado de
gtem de satisfazer o contrato de entrada def. - A ordem altera o resultado: para 3, quadrado após incremento dá 16; incremento após quadrado dá 10.