Covil Do Dev

Como utilizar a função lambda em Python

Neste artigo você aprenderá tudo sobre expressões lambda em Python. Verá como simplificar seu código, saberá onde utilizar e onde evitar.

Funções Anônimas

Funções anônimas estão presentes em muitas linguagens, em algumas sendo um conceito básico primordial da linguagem, é, por exemplo, o caso do LISP e do Haskell.

ad

História

As linguagens modernas que contém a função lambda em geral bebem da mesma fonte, um modelo computacional chamado “Lambda Calculus” inventado por Alonzo Church na década de 30.

Lambda Calculus e a lógica matemática são os precursores das linguagens funcionais, Python não é uma linguagem funcional, porém adotou desde o início (em 1994) alguns conceitos funcionais, com as funções reduce, map, filter e lambda.

que são funções anônimas?

Como o próprio nome já indica, função anônima é uma função não identificada, sem um “nome”, no caso, sem uma variável.

Na verdade, até podemos atribuí-las a uma variável, mas você verá no próximo tópico que isso não é uma boa prática.

Dependendo da linguagem a função lambda pode ser chamada por nomes diferentes, algumas variações que você poderá ver são:

  • Função anônima.
  • Função na forma lambda.
  • Função lambda.
  • Função literal.
  • Expressão lambda.
  • Abstração lambda.
  • Modelo lambda.

Função lambda em Python

Veremos alguns exemplos simples de utilização de uma função lambda, no decorrer do artigo realizaremos várias demonstrações, mas só para você ir se acostumando com a sintaxe, veja como é a forma básica de uso para somar dois números em Python.

lambda x, y: x + y

Definir a função lambda da forma acima não tem nenhuma utilidade prática, para utilizar com os parâmetros podemos efetuar da seguinte forma:

print((lambda x, y: x + y)(1, 2))
# 3

Também podemos armazenar a função lambda e utilizar em mais de um contexto.

funcao_soma = lambda x, y: x + y

print(funcao_soma(1, 2))
# 3

print(funcao_soma(10, -6))
# 4

Ao decorrer do artigo veremos outros exemplos e outras formas de utilizar as funções lambda em Python.

Utilizar a função lambda é uma boa prática?

Em Python as funções lambda dividem muitas opiniões, algumas pessoas defendem o seu uso por permitir simplificar(pelo menos em quantidades de linhas) os códigos em Python.

Ao mesmo tempo, existe um grupo que defende que as funções anônimas não são “Pythônicas”, inclusive existe um trecho no guia de estilo do Python(PEP 8), que diz:

“Sempre use uma instrução def em vez de uma instrução de atribuição que vincula uma expressão lambda diretamente a um identificador.”

Fora esse uso associado a uma variável não tem nenhuma outra restrição da função lambda no PEP 8.

Verá logo abaixo vários exemplos de bons usos, onde, em geral, utilizar a expressão lambda seria uma forma simples de resolver um problema.

Diferenças entre uma função lambda e uma função convencional

Funções lambda são semelhantes em muitos pontos em relação à forma convencional das funções, definidas com a diretiva def, algumas características próprias das funções lambda são:

  • Não podem conter outros comandos(statements), apenas expressões.
  • São definidas numa linha.
  • Não é possível utilizar tipagem.
  • Podem ser chamadas sem serem definidas previamente.

Analisaremos cada um dos pontos.

Não podem conter outros comandos(statements)

Em funções lambdas, diferentemente das convencionais, não é possível utilizar comandos como:

  • return
  • pass
  • assert
  • raise

Caso você tente utilizar irá ocorrer um erro de Syntax, isso pode ser um problema em alguns casos, afinal impossibilita tratar erros, mesmo os mais simples.

São definidas em uma linha

Esse ponto é auto explicativo, significa que as funções lambda são one line expression, ou expressões de uma linha, mesmo que, na prática, podemos utilizar mais de uma linha para defini-las.

funcao_soma = (lambda x, y:
               x + y)

Caso execute esse código acima verá que se trata de uma função válida.

Ser one line expression como escrito na documentação significa, na verdade, que se trata de uma única expressão, mesmo que separada em várias linhas diferentes.

Não é possível utilizar tipagem

Esse é um ponto interessante, muitos iniciantes acreditam que não existe tipagem em Python, mas isso é falso, como foi visto nesse artigo existe tipagem e utilizar traz uma série de vantagens.

Por exemplo, poderíamos definir a função normal de soma utilizando tipagem.

def funcao_soma(x: int, y: int) -> int:
    return x + y

Não é possível fazer algo semelhante com as funções lambda.

Podem ser chamadas sem serem definidas previamente

Com as funções lambda, como já demonstrado anteriormente, podemos passar os atributos sem defini-las.

print((lambda x, y: x + y)(1, 2))
# 3

Não é possível fazer isso com as funções convencionais definidas com a diretiva def.

Esse uso das funções lambda são normalmente chamadas IIFE(immediately invoked function execution) ou em português seria algo como EIFI(Execução imediata de função invocada), mas nunca vi esse termo sendo utilizado em português, caso tenha alguma referência de tradução/utilização envie-me por gentileza.

Passando parâmetros

Existem várias formas de passagem de parâmetros para uma função lambda, assim como para funções convencionais, algumas formas são:

  • Parâmetros posicionalmente
  • Parâmetros nomeadamente
  • Parâmetros em lista de tamanho variável(*args)
  • Parâmetros em lista de tamanho variável nomeadamente(**kwargs)

Exemplo em cada um dos tipos:

Parâmetros posicionalmente

A forma convencional de passar parâmetros para uma função.

funcao_soma = (lambda x, y: x + y)

print(funcao_soma(1, 2))
# 3

Parâmetros nomeadamente

Outra forma bem comum de se utilizar funções, um pouco mais descritiva, porém ainda simples e bem prático.

funcao_soma = (lambda x, y: x + y)

print(funcao_soma(x=1, y=2)
# 3

Também podemos nomear apenas o segundo parâmetro.

funcao_soma = (lambda x, y: x + y)

print(funcao_soma(1, y=2))
# 3

Parâmetros em lista de tamanho variável(*args)

Uma forma menos comum, mas útil em alguns casos onde a quantidade de parâmetros são variáveis, por exemplo, a nossa função soma das formas anteriores só somavam dois valores, poderíamos corrigir isso com esse estilo de passagem de parâmetro.

funcao_soma = (lambda *args: sum(args))

print(funcao_soma(1, 2, 3, 4, 5))
# 15

Parâmetros em lista de tamanho variável nomeadamente(**kwargs)

Forma também não muito utilizada, com exceção de quando se utiliza algum framework de UI que, em geral, adotam esse estilo de notação.

É bem útil quando é necessário realizar a distinção dos valores e a função tem uma grande variedade de parâmetros, mas esse não costuma ser caso de funções lambda, de qualquer forma essa opção existe e pode ser utilizada.

funcao_soma = (lambda **kwargs: sum(kwargs.values()))

print(funcao_soma(a=1, b=2, c=3))
# 6

Exemplos práticos de bom uso da função lambda em Python

As funções lambda muitas vezes são deixadas de lado por muitas pessoas, principalmente por não verem bons usos práticos para elas, mas existem algumas boas formas de se utilizar funções lambda sem tornar o código completamente ilegível.

Filtrando valores de uma lista com lambda

Digamos que deseja filtrar uma lista selecionando apenas os valores maiores que 5, isso poderia ser efetuado com a função filter e uma simples expressão lambda.

numeros = [1, 9, 20, 3, 41, 50, 0, -5]

print(numeros)
# [1, 9, 20, 3, 41, 50, 0, -5]

numeros = list(filter(lambda x: x > 5, numeros))

print(numeros)
# [9, 20, 41, 50]

Tratando uma lista de valores com lambda

Digamos que tenha uma lista com textos em minúsculos e gostaria da versão capitalizada desse texto, a função map em conjunto com uma expressão lambda simples pode ser utilizada para isto.

cores_minusculo = ['azul', 'branco', 'vermelho']

print(cores_minusculo)
# ['azul', 'branco', 'vermelho']


cores_maiusculo = list(map(lambda x: x.upper(), cores_minusculo))

print(cores_maiusculo)
# ['AZUL', 'BRANCO', 'VERMELHO']

Formatando um texto de uma lista de valores com lambda

Caso queira exibir os números separados por um -, isso também pode ser feito utilizando reduce e lambda.

from functools import reduce

numeros = [1, 9, 20, 3, 41, 50, 0]

print(numeros)
# [1, 9, 20, 3, 41, 50, 0]

numeros = reduce(lambda x1, x2: f'{x1} - {x2}', numeros)

print(numeros)
# 1 - 9 - 20 - 3 - 41 - 50 - 0

Ordenando uma lista com lambda

Esse é o exemplo onde a função lambda brilha, sem dúvidas utilizá-la como o parâmetro “key” das funções ordenadores é uma forma simples e elegante de resolver esse problema

exemplos = ['exemplo1', 'exemplo4',
            'exemplo2', 'exemplo33',
            'exemplo100', 'exemplo44']

print(exemplos)
# ['exemplo1', 'exemplo4',
# 'exemplo2', 'exemplo33',
# 'exemplo100', 'exemplo44']

exemplos = sorted(exemplos)

print(exemplos)
# ['exemplo1', 'exemplo100',
# 'exemplo2', 'exemplo33',
# 'exemplo4', 'exemplo44']

exemplos = sorted(exemplos,
                  key=lambda x: int(x.replace('exemplo', '')))

print(exemplos)
# ['exemplo1', 'exemplo2',
# 'exemplo4', 'exemplo33',
# 'exemplo44', 'exemplo100']

Utilização exagerada de funções lambda

Quando comecei a escrever esse artigo queria fazer o mais completo possível, cobrindo todas as possibilidades, semelhante ao que fiz no artigo sobre dicionários. Quando comecei a pesquisar sobre e ver como os outros sites e blogs estavam mostrando e ensinando as funções lambdas mudei de ideia.

As funções lambdas são ótimas para casos específicos, normalmente expressões simples que cabem numa linha, semelhantes aos exemplos na seção anterior, mas em alguns tutoriais na internet vi exemplos que estão realmente exagerados e a utilização de da expressão é completamente desnecessário ou muito exagerado e fora da realidade.

Cheguei a ver exemplos de testes unitários para expressões lambdas, qual a lógica disso? Não seria mais fácil definir uma função normal?

Outra coisa é a utilização de expressão lambda em classes, no PEP 8 diz que deve se evitar associar funções lambda a variável, porque alguém faria isso dentro de uma classe?

Conclusão

As funções lambda são e vão ser por natureza extremamente controversa, afinal a razão real delas existirem é para simplificar a definição de uma função, e isso muitas vezes acaba deixando o código confuso e ilegível.

Cabe a cada programador saber a hora exata de utilizá-las ou não, evitando sempre que isso deixará seu código desorganizado, afinal, não se esqueça do zen do Python “bonito é melhor que feio”, e definitivamente expressões lambda em excesso e nos locais errados não são bonitas.

Obrigado por visitar o blog e por ler esse artigo, se tive qualquer dúvida, ideia ou sugestão, não hesite em entrar em contato pelo meu e-mail: lindomar@covildodev.com.br