– Criando suas funções em Python – Functions no Python
Diversas vezes usamos funções nos nossos códigos. O Python já nos fornece dezenas delas! Mas e se eu faço uma operação frequentemente? Será que poderíamos criar uma função que atenda essa atividade?
Veja o exemplo ao lado. Um simples, apenas para entendermos o conceito.
Imagine que sempre precisamos calcular a media de 2 notas. Vamos criar uma função calcular_media que nos permita realizar essa operação.
#Operação rotineira: Cálculo da média
nota1 = input('Insira nota 1:')
nota2 = input('Insira nota 2:')
media = (float(nota1) + float(nota2))/2
print('A média das notas é : {}.'.format(media))
___________________
Insira nota 1:7
Insira nota 2:6
A média das notas é : 6,5.
#Criando uma função calcular_media:
def calcular_media(nota1,nota2):
nota1 = input('Insira nota 1:')
nota2 = input('Insira nota 2:')
media = (float(nota1) + float(nota2))/2
return print('A média das notas é : {}.'.format(media))
#Chamando a função que acabamos de criar
calcular média(10,5)
______________________
Insira nota 1:5
Insira nota 2:6
A média das notas é : 5,5.
Função calcular_media criada para esse programa que necessita de 2 parâmetros para rodar, nota1 (Ex:10) e nota2 (Ex:5).
Vamos entender a estrutura no Python para a criação de uma função.
def indica que uma função será definida.
def nome_da_função(argumento1, argumento2, argumentoN):
Ação 1 a ser realizada pela função;
Ação 2 a ser realizada pela função;
Ação 2 a ser realizada pela função;
return O que a função retornará ao rodar a função
– Retornar um valor na Function
Vamos voltar para nosso exemplo anterior onde calculamos a média de duas notas.
Primeiros vamos entender o que é “Retornar um valor”.
Como estamos falando em functions, estamos falando de criarmos um código que a partir de algum input ela processa os dados e retorna um resultado.
No nosso caso por exemplo:
Inputs → nota1 e nota2
Resultado retornado → Média das notas
Se olharmos o código da nossa função calcular_media, veremos que ao final temos uma linha RETURN. Essa linha informa o que será retornado nessa função. No nosso exemplo, um print com a média das notas. Essa resposta geralmente são: Listas, variáveis, dicionários, etc...
– Argumentos e parâmetros em uma Function
Como citamos no slide anterior, para que essa função funcione são necessários dois inputs:
• nota1;
• nota2.
Esses inputs são chamados de argumentos ou parâmetros.
Importante dizer que os argumentos não são obrigatórios.
Os argumentos serão sempre definidos dentro dos parênteses da nossa linha de código que se inicia com def.
– Aplicação em um Exemplo de argumento
Agora vamos ver um exemplo onde teremos que criar uma function para resolver o desafio. O desafio consiste em analisar uma lista de produtos e enviar instruções dizendo quais produtos devem ser enviados para a área de bebidas alcóolicas.
Cada produto tem um código, por exemplo:
Vinho → BEB12302
Guaraná → BSA11104
As bebidas não alcóolicas começam com BSA, enquanto
as bebidas alcóolicas começam com BEB.
def ehalcoolico(bebida):
bebida = bebida.upper()
if 'BEB' in bebida:
return True
else:
return False
produtos = ['beb46275','TFA23962','TFA64715','TFA69555','TFA56743','BSA45510','TFA44968','CAR75448','CAR23596','CAR13490','BEB21365','BEB31623','BSA62419','BEB73344','TFA20079','BEB80694','BSA11769','BEB19495','TFA14792','TFA78043','BSA33484','BEB97471','BEB62362','TFA27311','TFA17715','BEB85146','BEB48898','BEB79496','CAR38417','TFA19947','TFA58799','CAR94811','BSA59251','BEB15385','BEB24213','BEB56262','BSA96915','CAR53454','BEB75073']
#percorrer toda a minha lista de produtos
#pra cada produto, verificar se ele é bebida alcoolica
#se for bebida alcoolica, exibir a mensagem Enviar....
for produto in produtos:
if ehalcoolico(produto):
print('Enviar {} para setor de bebidas alcóolicas'.format(produto))
____________________________________
Enviar beb46275 para setor de bebidas alcóolicas
Enviar BEB21365 para setor de bebidas alcóolicas
Enviar BEB31623 para setor de bebidas alcóolicas
Enviar BEB73344 para setor de bebidas alcóolicas
Enviar BEB80694 para setor de bebidas alcóolicas
Enviar BEB19495 para setor de bebidas alcóolicas
Enviar BEB97471 para setor de bebidas alcóolicas
Enviar BEB62362 para setor de bebidas alcóolicas
Enviar BEB85146 para setor de bebidas alcóolicas
Enviar BEB48898 para setor de bebidas alcóolicas
Enviar BEB79496 para setor de bebidas alcóolicas
Enviar BEB15385 para setor de bebidas alcóolicas
Enviar BEB24213 para setor de bebidas alcóolicas
Enviar BEB56262 para setor de bebidas alcóolicas
Enviar BEB75073 para setor de bebidas alcóolicas
• Function que retorna True se a bebida for alcóolica e False se a bebida não for alcóolica.
• A lista de produtos é percorrida e cada produto é enviado como argumento da função ehalcoolico e testado se é uma bebida alcóolica.
• Caso seja uma bebida alcóolica, uma mensagem com o código do produto será printada.
– Vários parâmetros e tipos de parâmetros
Na nossa função Calcular_media, já usamos mais de um parâmetro.
Mas vamos entender alguns detalhes de como trabalhar com mais de um parâmetro de uma função.
Existem duas formas distintas de informar parâmetros para funções:
1) Em ordem (positional argument);
2) Com o nome do argumento (keyword argument)
Vamos entender essa diferença melhor olhando o exemplo ao lado:
Aqui temos uma função que classifica produtos baseado na sua categoria. Em especial, as bebidas, se são alcóolicas ou não.
def eh_da_categoria(bebida, cod_categoria):
bebida = bebida.upper()
if cod_categoria in bebida:
return True
else:
return False
Argumentos na mesma ordem:
#Usando ordem:
for produto in produtos:
if eh_da_categoria(produto,'BEB'):
print('Enviar {} para setor de bebidas alcóolicas'.format(produto))
elif eh_da_categoria(produto, 'BSA'):
print('Enviar {} para setor de bebidas não alcóolicas'.format(produto))
Argumentos por palavra chave:
#Usando palavra chave:
for produto in produtos:
if eh_da_categoria(cod_categoria = 'BEB', bebida=produto):
print('Enviar {} para setor de bebidas alcóolicas'.format(produto))
elif eh_da_categoria(produto, 'BSA'):
print('Enviar {} para setor de bebidas não alcóolicas'.format(produto))
ERRO!:
#Só podemos usar um método, o caso abaixo retornará erro:
for produto in produtos:
if eh_da_categoria(cod_categoria = 'BEB', produto):
print('Enviar {} para setor de bebidas alcóolicas'.format(produto))
elif eh_da_categoria(produto, 'BSA'):
print('Enviar {} para setor de bebidas não alcóolicas'.format(produto))
Vamos entender um pouco melhor o erro do slide anterior.
Quando usamos um parâmetro de keyword no início da declaração de parâmetros, devemos seguir usando Keywords para todos os outros argumentos.
Vamos entender um caso onde podemos usar tanto os argumentos de posição quanto de palavras-chaves em uma mesma linha de código. Vamos aproveitar para aprender um novo argumento: sep =
Este argumento nos ajuda a apresentar os dados separando-os conforme a informação que seja fornecida por nós.
Vamos para o exemplo:
qtde_produtos = len(produtos)
print('Quantidade total de produtos:', qtde_produtos, 'texto2', 'texto3', sep = '\n')
___________________
Quantidade total de produtos:
39
texto2
texto3
– Dicas e Exemplos com Argumentos em Function
Nessa aula vamos ver alguns exemplos de funções que já usamos e seus respectivos parâmetros (de palavras-chaves, de posicionamento ou sem parâmetros).
• upper() → não tem parâmetros
Se tentarmos passar algum valor como parâmetro no upper(), ocorrerá um erro.
cod_produto = 'beb12304'
print(cod_produto.upper())
_______________
BEB12304
• sort() → apenas parâmetros keyword
Ordenando uma lista em ordem decrescente através do método sort(). Para isso, devemos escrever: reverse = True.
O argumento reverse é um argumento de palavra-chave.
vendas_ano = [100, 200, 50, 90, 240, 300, 55, 10, 789, 60]
vendas_ano.sort(reverse = True)
print(vendas_ano)
___________________
[789, 300, 240, 200, 100, 90 60, 55, 50, 10]
Para saber mais sobre uma determinada função e quais tipos de parâmetros essa função aceita, o recomendado é que você faça uma pesquisa na documentação dessa função.
• extend(lista) → 1 parâmetro obrigatório
O extend possui 1 parâmetro de posição que recebe uma lista vendas_novdez e adiciona os itens dessa lista dentro da lista vendas_ano
vendas_ano = [100, 200, 50, 90, 240, 300, 55, 10, 789, 60]
vendas_novdez = [500, 1555]
vendas_ano.extend(vendas_novdez)
print(vendas_ano)
___________________
[100, 200, 50, 90, 240, 300, 55, 10, 789, 60, 500, 1555]
• Nossa função eh_da_categoria(bebida, cod_categoria) → 2 parâmetros de posição obrigatórios
A função eh_da_categoria possui 2 parâmetros de posição.
Dica: Quando você não se lembrar de quais valores determinada função precisa para funcionar, no jupyter e com o cursor no nome da função, você deverá pressionar SHIFT + TAB para as informações sobre essa função serem mostradas.
def eh_da_categoria(bebida, cod_categoria):
bebida = bebida.upper()
if cod_categoria in bebida:
return True
else:
return False
if eh_da_categoria(cod_produto, 'BEB'):
print('É uma bebida alcoolica')
___________________
É uma bebida alcoolica
– Valores padrões para argumentos
Já reparou que em algumas funções existem padrões já estabelecidos no Python? Não? Vamos para um caso:
Método .sort(). Sempre que fazemos este método, o padrão do Python é ordenar os dados de forma crescente como na figura ao lado. No entanto, podemos forçar o Python a não usar o padrão fornecendo a ele uma palavra-chave: sort(reverse = True)
Assim, a nossa lista será ordenada de forma decrescente. O que acontece aqui é que o padrão do Python omite sua configuração padrão: sort(reverse=False)
Isso acontece pois a função sort foi programada dessa forma!
vendas = [100,30,70,94,15,65,35]
vendas.sort()
print('Ordem crescente')
print(vendas)
vendas.sort(reverse=True)
print('Ordem decrescente')
print(vendas)
_______________
Ordem crescente
[15,30,35,65,70,94,100]
Ordem decrescente
[100,94,70,65,35,30,15]
O mais interessante, é que podemos fazer exatamente a mesma coisa nas funções criadas
por nós! Vamos para um exemplo que cria códigos de produtos. No entanto, temos duas possibilidades de código:
• Todo em letras maiúsculas (M);
• Todo em letras minúsculas (m).
Nosso padrão será minúsculas, mas o usuário poderá usar a palavra chave padrão=‘M’ para alterar para letras maiúsculas. Perceba que usamos o IF para definir o que
acontecerá dependendo do padrão fornecido pelo usuário.
Ao lado apresentamos a função e o resultado dos casos. Perceba que no primeiro caso o usuário não fornece nenhum argumento e o padrão MINÚSCULO é atendido.
def padronizar_codigos(lista_codigos, padrao='m'):
for i, item in enumerate(lista_codigos):
item = item.replace(' ', ' ')
item = item.strip()
if padrao == 'm':
item = item.casefold()
elif padrao == 'M':
item = item.upper()
lista_codigos[i] = item
return lista_codigos
cod_produtos = [' ABC12 ', 'abc34', 'AbC37']
print(padronizar_codigos(cod_produtos))
____________________
['abc12', 'abc34', 'abc37']
cod_produtos = [' ABC12 ', 'abc34', 'AbC37']
print(padronizar_codigos(cod_produtos,padrao='M'))
____________________
['ABC12', 'ABC34', 'ABC37']
– Falando um pouco mais dos returns das functions
Como vimos anteriormente o return nos retorna sempre o “resultado” da nossa função.
É possível retornar booleans, integers, floats, variáveis, etc.
No entanto, é muito importante explicar que o return funciona como um FIM de uma função. Ou seja, se a função chegar até a linha de código RETURN ela irá encerrar a função mesmo que se trate de um FOR como no exemplo ao lado.
Essa função não faz muito sentido de existir, mas podemos ver que apesar de termos definido que nossa função retorna o valor i com um range de 5, apenas o valor 0(PRIMEIRA ITERAÇÃO DO FOR) foi retornado. Por que? Porque ao chegar ao return, a nossa função chega ao FIM.
def fazer_for():
for i in range(5):
return i
print(fazer_for())
________________
0
Ao chegarmos nessa linha de código, a função será interrompida. Ou seja, só haverá UMA iteração no FOR e não CINCO como definimos no RANGE
Retorno esperado: 0 ,1,2,3,4
Retorno obtido: 0 → Apenas a primeira iteração do FOR
– Return com mais de uma informação
Vamos aprofundar um pouco mais no RETURN. Nossas funções até agora, em geral, são simples e possuem retornos igualmente simples com apenas um valor por exemplo.
No entanto, é possível que o retorno necessário seja um pouco mais complexo com mais
resultados. Ao lado temos uma função ainda bem simples, mas que nos permite entender o conceito. Dentro da nossa função operações_básicas calculamos resultados como soma, diferença, multiplicação e divisão.
Uma informação importante é que o retorno é uma TUPLA. Isso nos permitirá trabalhar melhor com esses dados.
def operacoes_basicas(num1, num2):
soma = num1 + num2
diferenca = num1 - num2
mult = num1 * num2
divisao = num1 / num2
return soma, diferenca, mult, divisao
print(operacoes_basicas(10, 2))
______________________
(12, 8, 20, 5.0)
• Ao invés de apenas 1 resultado, temos 4 resultados da nossa função.
• Retorno de todas as variáveis calculadas dentro da função em uma TUPLA.
Vamos para um caso um pouco mais complexo.
Nesse caso estamos avaliando quais vendedores bateram a meta. Podemos perceber que nossa função retorna uma tupla com 2 valores:
• % que bateram a meta(perc_baterammeta);
• Pessoas que bateram a meta (vendedores_acima_media)
meta = 1000
vendas = {
'João':15000,
'Julia':27000,
'Marcus':9900,
'Maria':3750,
'Ana':10300,
'Alon':7870,
}
def calculo_meta(meta,vendas):
bateram_meta = []
for vendedor in vendas:
if vendas[vendedor]>=meta:
bateram_meta,append(vendedor)
perc baterammeta = len(bateram_meta)/len(vendas)
return perc_baterammeta, bateram_meta
p_meta, vendedores_acima_meta = calculo_meta(meta,vendas)
print(p_meta)
print(vendedores_acima_meta)
_________________
0.5
['João', 'Julia', ' Ana']
• Retorno da função será uma TUPLA
– Docstrings e annotations
Não obrigatoriamente todas as funções criadas serão usadas apenas por você, por isso é
importante que elas sejam organizadas e compreensíveis por outras pessoas. Essa organização passa pelos:
Docstrings : Iniciados por ‘’’ permitem strings de mais de uma linha. Aqui você pode descrever o que sua função faz, argumentos que ela possui, etc. Você pode criar o seu padrão, mas caso não possua um, temos um exemplo no print ao lado.
def minha_funcao(arg1,arg2,arg3):
''' O que minha função faz.
Meus argumentos:
arg1(tipo do meu argumento):Comentário sobre o argumento
arg2(tipo do meu argumento):Comentário sobre o argumento
arg3(tipo do meu argumento):Comentário sobre o argumento
return
O retorno da minha função
'''
soma = arg1+arg2+arg3
return soma
minha_função()
• Informações podem ser acessadas usando SHIFT+TAB quando o cursor estiver na função desejada
Signature: minha_funcao(arg1, arg2, arg3)
Docstring:
O que minha função faz.
Meus argumentos:
arg1(tipo do meu argumento):Comentário sobre o argumento
arg2(tipo do meu argumento):Comentário sobre o argumento
arg3(tipo do meu argumento):Comentário sobre o argumento
Não obrigatoriamente todas as funções criadas serão usadas apenas por você, por isso é
importante que elas sejam organizadas e compreensíveis por outras pessoas.
Essa organização passa pelos:
Annotations : É uma versão mais simplificada de um docstrings. As informações sobre a função são escritas dentro da própria função ao ser definida.
def minha_funcao(arg1: int , arg2: float , arg3: int) -> float:
return arg1 + arg2 + arg3
minha_funcao(1,5.1,3)
___________________
9.1
– Exceções e erros em funções
Até agora, sempre que nossos códigos acusavam algum erro, significava que seu programa seria encerrado. No entanto, pode ocorrer uma situação em que o resultado ou o valor inserido pelo usuário está errado, mas você não quer que ele pare nesse momento, e sim que o corrija.
Para esses casos podemos usar o TRY e o EXCEPT.
SEMPRE que o TRY for utilizado, deverá haver um EXCEPT
try:
o que eu quero tentar fazer
except:
o que vou fazer caso dê erro
• Indentação indica que essas linhas pertencem ao TRY e EXCEPT
Primeiro vamos entender o que são os erros na realidade. Sabemos que são um pouco assustadores, principalmente no começo. Milhões de linhas de código que não são fáceis de entender. Vamos pegar um exemplo para analisar e depois vamos voltar para nosso TRY e EXCEPT e como usá-lo.
print(erro)
_____________
NameError: name 'erro' is not defined
Bem, agora que entendemos um pouco mais sobre a estrutura de um erro fornecido pelo Python, vamos usar o Try e Except para criar o nosso próprio erro, que nos permita informar ao usuário. Vamos criar uma função que indica qual o tipo de e-mail utilizado pelo usuário. Perceba que no bloco EXCEPT usamos ao invés do return, o RAISE. Isso fará com que um erro seja exibido ao usuário. Veremos isso melhor:
def descobrir_servidor(email):
try:
posicao_a = email.index('@')
except:
raise ValueError('Email digitado não tem @, digite novamente')
else:
servidor = email[posicao_a:]
if 'gmail' in servidor:
return 'gmail'
elif 'hotmail' in servidor or 'outlook' in servidor or 'live' in servidor:
return 'hotmail'
elif 'yahoo' in servidor:
return 'yahoo'
elif 'uol' in servidor or 'bol' in servidor:
return 'uol'
else:
return 'não determinado'
email = input('Qual o seu e-mail?')
print(descobrir_servidor(email))
Bem, agora que entendemos um pouco mais sobre a estrutura de um erro fornecido pelo Python, vamos usar o Try e Except para criar o nosso próprio erro, que nos permita informar ao usuário. Vamos criar uma função que indica qual o tipo de e-mail utilizado pelo usuário. Perceba que no bloco EXCEPT usamos ao invés do return, o RAISE. Isso fará com que um erro seja exibido ao usuário. Veremos isso melhor:
def descobrir_servidor(email):
try:
posicao_a = email.index('@')
except:
raise ValueError('Email digitado não tem @, digite novamente')
else:
____________________________
Qual seu email?hashtaggmail.com
--------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [6], in descobrir_servidor(email)
2 try:
----> 3 posicao_a = email.index('@')
4 except:
ValueError: substring not found
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
Input In [7], in <cell line: 2>()
1 email = input('Qual o seu e-mail?')
----> 2 print(descobrir_servidor(email))
Input In [6], in descobrir_servidor(email)
3 posicao_a = email.index('@')
4 except:
----> 5 raise ValueError('Email digitado não tem @, digite novamente')
6 else:
7 servidor = email[posicao_a:]
ValueError: Email digitado não tem @, digite novamente
↖ Usuário digita e-mail sem @. Erro personalizado
– Múltiplos Argumentos para uma Function
Voltando para o nosso exemplo de cálculo de média das notas. No caso anterior criamos 2
argumentos nota1 e nota2, existe uma outra forma que podemos fazer essa declaração de
variáveis. Você verá em alguns lugares durante pesquisas o termo *args.
Usando o * antes da variável indicamos que não estamos tratando de um argumento único e sim um argumento que poderá receber um número ilimitado de valores.
Podemos ver no exemplo que ao usarmos *notas permitimos não só ter apenas 2 notas mas 3, 4 ,5 ou 10...
• Ao invés de limitar o número de notas, criamos um argumento de tamanho variável
def calcular_media(*notas)
soma=0
for nota in notas:
soma += nota
return soma/(len(notas))
print(calcular_media(10,0,5,6,7,8,9,1,0,4,8,6,4,8,9,4,2,2,2,3,4,5,8,9))
print(calcular_media(10,0))
_________________
5.166666666666667
5.0
Como vimos, temos tanto argumentos de posição como argumentos Keywords (palavras-chave). O conceito é exatamente o mesmo usado no exemplo anterior. Ao usarmos o ** antes da palavra-chave, temos uma função que aceita receber diversas palavras chaves na função. Esse conceito é comumente visto com **kwargs.
Ao lado temos um exemplo deste caso. Aqui o usuário poderá (ou não) passar informações para que influenciem no preço final do produto. No caso dos **kwargs, é importante entender o que a função faz. Olhando dentro da nossa função preco_final, vemos que existem três variáveis que influenciam o preço:
• desconto;
• garantia_extra;
• Imposto.
def preco_final(preco, **adicionais):
print(adicionais)
if 'desconto' in adicionais:
preco *= (1 - adicionais['desconto'])
if 'garantia_extra' in adicionais:
preco += adicionais['garantia_extra']
if 'imposto' in adicionais:
preco *= (1 + adicionais['imposto'])
return preco
print(preco_final(1000, desconto=0.1, garantia_extra = 100, imposto=0.3))
____________________________
{'desconto': 0.1, 'garantia_extra': 100, 'imposto': 0.3}
1300.0
• Perceba que mesmo sem usar todos os argumentos nosso valor final foi calculado.
– Ordem dos Tipos de Argumento
Ok. Entendi que tenho liberdade de ter *args ou **kwargs, mas por enquanto só vimos isso separadamente. E se eu tiver um caso mais confuso com 3 kwargs, 2 args? Tem um jeito certo de fazer? Ou é só sair colocando?
Temos 2 regras para seguir:
1) Primeiro colocamos os argumentos de posição (args), depois os de palavra chave (kwargs).
2) Seguindo a ordem anterior, primeiro fazemos os argumentos simples (sem * ou **) e depois os múltiplos (com * ou **).
Vamos dar uma olhada no estrutura abaixo para entendermos melhor.
def minha_funcao(arg1, arg2, arg3, arg4, *args, k = kwarg1, k2 = kwarg2, k3 = kwarg3, **kwargs):
Nenhum comentário:
Postar um comentário