Modulo 017 – Functions usadas como parâmetro e Expressões Lambda

 – Functions usadas como parâmetro e Expressões Lambda – Functions em Iterables
e a função map

Veremos agora alguns casos que nos permitem usar funções dentro de funções. Na prática eles farão o papel do List Comprehension. Novamente, não são linhas de código obrigatórias, pois existem formas de escrever o código da mesma forma sem o uso destas funções.
A primeira função que veremos é o MAP. Ela nos permite aplicar uma função a cada um dos itens de um iterable. Lembrando que os iterables são listas, dicionários, strings etc.
Abaixo definimos o formato padrão de uma expressão MAP:

 lista = list(map(função, iterable_original)) 

Voltando para nosso exercício de padronização de códigos, vamos entender como poderíamos usar a função MAP para responder este caso. Perceba que primeiro definimos uma função que padroniza os códigos.
Usamos a função definida DENTRO do argumento do MAP juntamente da lista PRODUTOS que é um iterable. Perceba que assim como vimos com a função ZIP, a função MAP nos retorna um OBJETO que precisa ser transformado em uma lista, assim como é realizado na última célula do jupyter.

 def padronizar_texto(texto): 
     texto = texto.casefold() 
     texto = texto.replace("  ", " "
     texto = texto.strip() 
     return texto 

• Agora queremos padronizar uma lista de códigos:

 produtos = [' ABC12 ', 'abc34', 'AbC37', 'beb12', ' BSA151', 'BEB23'

 produtos = map(padronizar_texto, produtos) 
 print(produtos) 
___________________
 <map object at 0x00000202D54F0AC0> 

 produtos = list(map(padronizar_texto, produtos)) 
 print(produtos) 
___________________
 ['abc12', 'abc34', 'abc37', 'beb12', 'bsa151', 'beb23'] 

Vamos olhar mais a fundo o que está ocorrendo dentro da função map do exemplo anterior. Veja a função MAP como uma espécie de linha de produção.
O que ela faz é pegar cada um dos itens do ITERABLE(no nosso caso a lista produtos) e passar esse item pela função indicada(nesse caso padronizar_texto). O resultado dessa linha de produção é um grande pacote de itens transformados em algo de acordo com a função indicada.

– Aplicando function em iterable no sort

Já conhecemos o método .sort() aplicável a listas. Quando usamos esse método para lista de strings por exemplo, a ordem não será alfabética e sim seguindo
a tabela ASCII. (exemplo ao lado) 
O Python nos permite fornecer algum critério chave para que a ordem seja realizada.
Para isso usaremos o argumento key= dentro da nossa função .sort.
Key indica que um critério específico será fornecido. Nesse caso, casefold (letras minúsculas).
Perceba que foi necessário o str, pois casefold é um método de STRINGS

 produtos = ['apple tv', 'mac', 'IPhone x', 'IPhone 11', 'IPad', 'apple watch', 'mac book', 'airpods'
 produtos.sort() 
 print(produtos) 
_____________________________
 ['IPad', 'IPhone 11', 'IPhone x', 'airpods', 'apple tv', 'apple watch', 'mac', 'mac book'] 

• Ordenado segundo a tabela ASCII

 produtos.sort(key=str.casefold) 
 print(produtos) 
____________________
 ['airpods', 'apple tv', 'apple watch', 'IPad', 'IPhone 11', 'IPhone x', 'mac', 'mac book'] 

– Lambda expressions
As lambda expressions são mais um conceito que não é obrigatório, mas é bem comum no mercado de trabalho e certamente irá surgir em códigos que você venha a ler no futuro. Ela funciona como uma versão simplificada da função que nós criamos usando def, etc... A Lambda é uma função Anônima. Ela não é chamada como as funções que vimos até agora. Ela é uma função local, que só funciona dentro de uma variável que definirmos.
Chamamos de anônima, pois não é necessário chamá-la como fazíamos com as funções “normais”. Antes de irmos para um exemplo, vamos entender sua estrutura.

 variável = lambda parâmetro: expressão 

• Variável que receberá os dados calculados.
• Indicação que será criada uma função lambda
• Equivalente aos argumentos indicados nos parênteses das funções: def nome_função (parâmetro)
• Equivalente as linhas de código dentro da indentação das funções: def minha_função(arg): expressão

Vamos analisar agora um exemplo real. O desafio é criar uma função que calcule o imposto devido, baseado no preço de um produto. Criamos uma função “normal” e uma lambda para que seja possível compará-las. Perceba que a função lambda nos permite declarar toda a função em apenas uma linha. No entanto, o mesmo resultado pode ser obtido usando a função convencional.

 imposto = 0.3 

 #criando uma função "normal"
 def preco_imposto(preco): 
     return preco * (1 + 0.3
 print(preco_imposto(100))

 #criando uma função "lambda"
 preco_imposto2 = lambda preco: preco * (1.0 + imposto) 

 print(preco_imposto2(100)) 
__________________
 130.0 
 130.0 

– A grande utilidade de Lambda Expressions

Nas aulas passadas vimos a função map e o método sort. Eles possuem um argumento que recebe uma função. Essa função normalmente é criada antes, para depois ser passada como parâmetro. Mas se a função for muito simples, você pode passar lambda
expressions como parâmetro. Então, a principal utilidade de lambda expressions está em não precisar criar uma função previamente para passá-la depois como parâmetro.
Agora vamos relembrar alguns métodos de dicionário e vamos ver alguns exemplos de aplicação usando o dicionário preco_tecnologia

 preco_tecnologia = {'notebook asus': 2450, 'iphone': 4500, 'samsung galaxy': 3000, 'tv samsung': 1000, 'ps5': 3000, 'tablet': 1000, 'notebook dell': 3000, 'ipad': 3000, 'tv philco': 800, 'notebook hp': 1700
 print(preco_tecnologia) 
____________________________
 {'notebook asus': 2450, 'iphone': 4500, 'samsung galaxy': 3000, 'tv samsung': 1000, 'ps5': 3000, 'tablet': 1000, 'notebook dell': 3000, 'ipad': 3000, 'tv philco': 800, 'notebook hp': 1700} 

 print(preco_tecnologia.items()) 
________________________
 dict_items([('notebook asus': 2450), ('iphone': 4500), ('samsung galaxy': 3000), ('tv samsung': 1000), ('ps5': 3000), ('tablet': 1000), ('notebook dell': 3000), ('ipad': 3000), ('tv philco': 800), ('notebook hp': 1700)]) 

 print(preco_tecnologia.keys()) 
________________________
 dict_keys(['notebook asus', 'iphone', 'samsung galaxy', 'tv samsung', 'ps5', 'tablet', 'notebook dell', 'ipad', 'tv philco', 'notebook hp']) 

 print(preco_tecnologia.values()) 
________________________
 dict_values([2450, 4500, 3000, 1000, 3000, 1000, 3000, 3000, 800, 1700]) 

• Usando o map()
Neste primeiro exemplo, queremos saber o preço de cada produto do dicionário adicionando o valor do imposto de 30% sobre o valor do produto. Faremos de 2 formas: a primeira definindo uma função previamente, e a segunda passando uma lambda
expression como parâmetro.

 #Fazendo por function 
 def calcular_preco(preco): 
     return preco * 1.3 

 preco_com_imposto = list(map(calcular_preco,   preco_tecnologia.values())) 
 print(preco_com_imposto) 
_______________________
 [3185.0, 5850.0, 3900.0, 1300.0, 3900.0, 1300.0, 3900.0, 3900.0, 1040.0, 2210.0] 

 #fazendo por lambda 
 preco_com_imposto2 = list(map(lambda preco: preco * 1.3 , preco_tecnologia.values())) 
 print(preco_com_imposto2) 
_______________________
 [3185.0, 5850.0, 3900.0, 1300.0, 3900.0, 1300.0, 3900.0, 3900.0, 1040.0, 2210.0]

• Lembrando que o método values() nos dá uma lista somente com os valores do dicionário, que nesse caso é o que nos interessa para o cálculo.

A segunda função que veremos neste módulo é o FILTER. O FILTER filtra um iterable com a ajuda de uma função (passada como parâmetro) que testa todos os elementos do iterable e retorna somente aqueles elementos que satisfazem à condição da função de teste, ou seja, todos os elementos do iterable que fazem a função retornar True como resposta.

Função filter. O primeiro argumento é a função que testa se cada elemento do iterable (segundo argumento) satisfaz a uma condição

 filter(função, iterable) 

Lembrando que a função a ser passada como parâmetro fará uma comparação e deverá ter retorno booleano (True ou False). O resultado da função filter é um filter object.

Por isso, teremos que usar a seguinte estrutura:

 lista = list(filter(função, iterable)) 

• Lista que receberá os dados após a aplicação da função FILTER
• Função List que transformará o resultado da função FILTER em uma lista
• Função filter. O primeiro argumento é a função, que testa se cada elemento do iterable (segundo argumento) satisfaz a uma condição

• Usando o filter()
Neste exemplo com filter, queremos apenas os produtos que custam acima de 2000. Faremos também de 2 formas: a primeira definindo uma função previamente, e a segunda passando uma lambda expression como parâmetro.

 print(preco_tecnologia.items()) 
________________________
 dict_items([('notebook asus': 2450), ('iphone': 4500), ('samsung galaxy': 3000), ('tv samsung': 1000), ('ps5': 3000), ('tablet': 1000), ('notebook dell': 3000), ('ipad': 3000), ('tv philco': 800), ('notebook hp': 1700)]) 

 #fazendo por function
 #print(preco_tecnologia.items())
 def ehmaior2000(item):
     return item[1] > 2000

 produtos_acima2000 = dict(list(filter(ehmaior2000, preco_tecnologia.items())))
 print(produtos_acima2000)
____________________
 {'notebook asus': 2450, 'iphone': 4500, 'samsung galaxy': 3000, 'ps5': 3000, 'notebook dell': 3000, 'ipad': 3000} 

 #fazendo por lambda 
 produtos2_acima2000 = dict(list(filter(lambda item: item[1] > 2000 , preco_tecnologia.items()))) 
 print(produtos2_acima2000) 
____________________
 {'notebook asus': 2450, 'iphone': 4500, 'samsung galaxy': 3000, 'ps5': 3000, 'notebook dell': 3000, 'ipad': 3000} 

Lembrando que o método items() nos dá uma lista com as chaves e os valores do dicionário, que nesse caso é o que nos interessa , pois queremos saber todos os produtos que custam acima de 2000

– Lambda Expressions para criar um Construtor de Funções

Agora vamos ver mais uma aplicação de lamba expressions, que é criar um “gerador de funções”. Basicamente, quando criarmos uma função com def, usaremos lambda expressions dentro dela.
Um exemplo de aplicação de “gerador de funções” é criar uma função que permita calcular o valor acrescido de imposto de diferentes categorias (produto, serviço, royalties, etc). Considerando os seguintes impostos:
• Produtos = 0.1 (10%)
• Serviços = 0.15 (15%)
• Royalties = 0.25 (25%)

 def calcular_imposto(imposto):
     return lambda preco: preco * (1 + imposto)

 # produto 0.1
 #serviço 0.15
 #royalties 0.25

 calcular_preco_produto = calcular_imposto(0.1
 calcular_preco_servico = calcular_imposto(0.15
 calcular_preco_royalties = calcular_imposto(0.25

• A função calcular_imposto() recebe imposto como parâmetro. E então o imposto é aplicado em uma função que recebe preco como parâmetro.
Como o retorno da função calcular_imposto é uma lambda expression, isso torna calcular_imposto um construtor de funções
• Cada uma dessas agora são funções que recebem preco como parâmetro e multiplica por (1 + imposto), onde o imposto de cada função está entre parênteses.

Agora vamos passar o valor 100 como parâmetro, e ver o que obtemos como resposta das funções que foram criadas.

 print((calcular_preco_produto(100))) 
 print((calcular_preco_servico(100))) 
 print(calcular_preco_royalties(100)) 
__________________
 110.00000000000001 
 114.99999999999999 
 125.0 

Podemos ver que a resposta de cada função está de acordo com os impostos que definimos anteriormente para cada função. Perceba também que alguns números tiveram muitas casas decimais. Isto tem a ver com a forma como o computador armazena esses valores na memória.

Podemos corrigir isso usando a função round(), como na imagem ao lado.

 print(round(calcular_preco_produto(100),2)) 
 print(round(calcular_preco_servico(100),2)) 
 print(round(calcular_preco_royalties(100),2)) 
___________________________
 110.0 
 114.0 
 125.0 

A aplicação de lambda expressions que vimos nesta aula é menos usual do que as formas que vimos anteriormente. Mas esta forma foi apresentada, pois em algum momento poder ser útil para você.

Nenhum comentário:

Postar um comentário