Funções: dividir para conquistar
Até agora nossos programas foram uma sequência única de comandos. Hoje vamos dar nome a pedaços de código, reaproveitá-los quantas vezes quisermos e montar programas maiores a partir de partes pequenas e testáveis.
Navegação: ← → trocam de etapa · V alterna entre etapas e página única · M sumário · F tela cheia · + − tamanho do texto · dentro do código, Ctrl+Enter executa.
Todo código desta aula pode ser editado e executado aqui mesmo. Altere os exemplos à vontade; o botão ↺ restaura o original. Suas alterações ficam salvas neste navegador; em Progresso você pode baixá-las em um arquivo e continuar em outro computador.
Nos exercícios, o botão ✓ Verificar testa seu código com várias entradas e mostra o que está certo e o que falta.
Por que precisamos de funções?
Veja o primeiro programa ao lado: o mesmo cálculo de média aparece três vezes. Se a regra mudar (por exemplo, a segunda prova passar a valer o dobro), teremos de corrigir três lugares e torcer para não esquecer nenhum.
Uma função é um bloco de código com nome. Escrevemos o bloco uma vez e o chamamos pelo nome sempre que precisarmos.
- Reaproveitamento: escreve uma vez, usa muitas.
- Organização: cada função resolve um pedaço do problema.
- Correção: um erro corrigido na função fica corrigido em todos os usos.
Você já usa funções
Desde a primeira aula usamos funções prontas do Python. Toda chamada tem a mesma forma: nome(argumentos). A função recebe valores, faz um trabalho e, quase sempre, devolve um resultado.
| Função | Recebe | Devolve |
|---|---|---|
len(x) | uma sequência | o tamanho |
max(a, b) | valores | o maior |
round(x, 1) | número e casas | número arredondado |
input(msg) | a pergunta | o texto digitado |
int(texto) | um texto | o número inteiro |
print(x) | valores | nada (None): só mostra |
Definindo uma função
def saudacao(nome):
texto = "Olá, " + nome + "!"
print(texto)linha é apenas o nome da função; nada é executado. Experimente trocar linha() por linha.Definir não é executar
Quando o Python encontra um def, ele apenas guarda a função com aquele nome. O corpo só roda quando a função é chamada, e roda de novo a cada chamada.
Na chamada, a execução salta para dentro da função, executa o corpo e depois volta para a linha seguinte de quem chamou.
Por isso a função precisa ser definida antes da primeira chamada. A forma mais comum de organizar: todas as definições no topo do arquivo, o programa principal embaixo.
Parâmetros e argumentos
| Termo | Onde aparece | Exemplo |
|---|---|---|
| parâmetro | na definição: é uma variável da função | def area(base, altura): |
| argumento | na chamada: é o valor enviado | area(3, 4) |
Na chamada, cada argumento é entregue ao parâmetro na mesma posição: o 1º argumento vai para o 1º parâmetro, e assim por diante. É como se o Python fizesse base = 3 e altura = 4 antes de começar o corpo.
O argumento pode ser qualquer expressão: um número, uma variável, uma conta ou até o resultado de outra função.
Teste de mesa: o caminho de uma chamada
Acompanhe o salto para dentro da função e a volta. Repare que base, altura e a só existem durante a chamada: quando a função termina, elas somem da tabela.
base e altura são criadas de novo com os valores novos.Desafio: moldura de texto
Crie uma função moldura(texto) que mostre o texto dentro de uma moldura de asteriscos, com um espaço de cada lado. A moldura deve se ajustar ao tamanho do texto.
| Chamada | Saída |
|---|---|
moldura("Python") | ********** * Python * ********** |
Depois, chame a função para três palavras diferentes.
Mostrar uma solução
return: devolvendo um valor
return valor encerra a função e entrega o valor para quem chamou. A chamada passa a “valer” esse resultado, como len("abc") vale 3.
Com o valor em mãos, quem chamou decide o que fazer: guardar em uma variável, usar em uma conta, comparar em um if ou passar para outra função.
dobro(2) vira 4, e então dobro(4) vira 8.print ou return?
Esta é a confusão mais comum da aula. print mostra um valor na tela, para a pessoa. return devolve um valor para o programa, que pode continuar usando-o.
Mostra, mas não devolve
Devolve: quem chamou decide
return devolve None, o valor que representa “nada”. Regra prática: funções que calculam algo devem usar return; deixe o print para o programa principal, que decide como mostrar o resultado.return encerra a função
Assim que um return é executado, a função termina na hora, mesmo que existam mais linhas depois dele ou que esteja no meio de um laço.
Isso permite escrever vários return, um para cada caso. Depois que um caso foi resolvido, não é preciso else: se a execução chegou à linha seguinte, é porque o return anterior não aconteceu.
return. Se nenhum caso for atendido e a função chegar ao fim, ela devolve None. Teste conceito(-1) e veja.Funções que respondem sim ou não
Uma função pode devolver True ou False. Costumamos dar nomes que soam como pergunta: eh_par, eh_primo, tem_vogal. O return dentro do laço encerra a busca assim que a resposta é conhecida.
Quando a função devolve um bool, a chamada vai direto no if ou no while, e o código fica parecido com uma frase: if eh_par(n):.
Uma comparação já é True ou False. Por isso return n % 2 == 0 substitui um if inteiro.
Devolvendo mais de um valor
Um return só pode entregar um valor, mas esse valor pode ser uma tupla. Basta separar os resultados por vírgula: return a, b.
Quem chamou recebe a tupla e pode desempacotá-la em várias variáveis, como vimos na aula de coleções.
Desafio: calculadora de IMC
- Crie
calcular_imc(peso, altura), que devolve peso ÷ altura². - Crie
classificar_imc(imc), que devolve o texto da classificação. - No programa principal, leia peso e altura, chame as duas funções e mostre o resultado com uma casa decimal.
| IMC | Classificação |
|---|---|
| menor que 18.5 | abaixo do peso |
| de 18.5 até menor que 25 | peso normal |
| de 25 até menor que 30 | sobrepeso |
| 30 ou mais | obesidade |
print ou input: elas só calculam e devolvem.Mostrar uma solução
Variáveis locais
Variáveis criadas dentro de uma função, inclusive os parâmetros, são locais: nascem quando a função é chamada e desaparecem quando ela termina.
Fora da função, esses nomes não existem. A única forma de um resultado sair da função é pelo return.
Duas funções podem usar o mesmo nome de variável sem conflito: cada uma tem o seu próprio espaço de nomes, chamado escopo.
total fora da função. Peça para a turma prever o resultado.Locais e globais
Variáveis criadas fora de qualquer função são globais. Quando uma função atribui um valor a um nome, ela cria uma variável local com esse nome, mesmo que exista uma global igual. A global não é alterada.
Uma função até consegue ler uma variável global, mas depender disso deixa o código difícil de entender: o resultado muda conforme coisas que estão fora da função.
E se a função atribuir a esse nome em qualquer ponto do corpo, o Python passa a considerá-lo local na função inteira. Usar antes de atribuir gera UnboundLocalError.
global, mas evite-a.)Listas como argumento
Lembra de “dois nomes, uma lista”? Passar uma lista para uma função funciona do mesmo jeito: o parâmetro vira outro nome para a mesma lista.
Por isso, se a função alterar a lista (append, lista[i] = ..., remove), a alteração aparece para quem chamou.
Com números, strings e tuplas isso não acontece: como são imutáveis, a função não tem como modificá-los.
lista.sort()), ou cria uma lista nova e a devolve (como sorted(lista)).Parâmetros com valor padrão
Um parâmetro pode ter um valor padrão, usado quando a chamada não envia aquele argumento: def saudar(nome, saudacao="Olá"):.
Você já usou isso sem perceber: round(x) arredonda para inteiro porque o número de casas tem padrão; print tem sep=" " e end="\n" como padrões.
def f(a=1, b): é erro de sintaxe.Argumentos nomeados
Na chamada, podemos dizer a qual parâmetro cada valor se destina: nome=valor. Assim a ordem deixa de importar e a chamada fica autoexplicativa.
É muito útil quando a função tem vários parâmetros com padrão e queremos mudar só um deles, por exemplo só o simbolo de linha.
Você também já viu isso: print(..., end="") e lista.sort(reverse=True).
f(1, b=2) funciona, f(a=1, 2) não.Desafio: formatando preços
Crie a função formatar_preco(valor, moeda="R$", casas=2), que devolve um texto com a moeda, um espaço e o valor com a quantidade de casas pedida.
| Chamada | Devolve |
|---|---|
formatar_preco(12.5) | 'R$ 12.50' |
formatar_preco(3.456, casas=1) | 'R$ 3.5' |
formatar_preco(9.9, "US$") | 'US$ 9.90' |
formatar_preco(7, moeda="€", casas=0) | '€ 7' |
Dica: dentro das chaves de uma f-string, a quantidade de casas pode vir de uma variável: f"{valor:.{casas}f}".
Mostrar uma solução
Funções chamando funções
Uma função pode chamar outras funções. Assim, um problema grande é quebrado em partes pequenas, cada uma fácil de escrever e de testar sozinha.
Durante a execução, o Python guarda uma pilha de chamadas: cada chamada em andamento fica empilhada sobre quem a chamou e, ao terminar, sai da pilha e devolve o resultado para quem está logo abaixo.
Organizando um programa
Um programa com funções costuma seguir este formato:
- Definições no topo, cada uma com um nome que diga o que ela faz (um verbo ajuda:
calcular_,ler_,mostrar_). - Um programa principal curto no final, que lê os dados, chama as funções e mostra os resultados.
A primeira linha do corpo pode ser um texto entre aspas triplas, a docstring, que documenta o que a função recebe e devolve.
Funções também evitam repetição de input: ler_opcao só devolve uma opção depois que ela for válida.
Módulos: funções prontas para importar
Um módulo é um arquivo com funções prontas. O Python traz vários; para usar, basta importar.
| Forma | Como chamar |
|---|---|
import math | math.sqrt(16) |
from math import sqrt | sqrt(16) |
import random | random.randint(1, 6) |
notas.py) e ser importadas em outros programas com import notas.Desafio: refatorando com funções
O programa ao lado funciona, mas repete o mesmo trecho para cada aluno. Refatore: reescreva-o com funções, sem mudar o que ele mostra.
media(n1, n2, n3)devolve a média.situacao(m)devolve"aprovado"ou"reprovado".mostrar(nome, n1, n2, n3)usa as duas anteriores e mostra a linha do aluno.
Depois, acrescente um quarto aluno: com funções, deve bastar uma linha.
Mostrar uma solução
Resumo da aula
| Conceito | Sintaxe | Lembre |
|---|---|---|
| Definição | def nome(p1, p2): | só guarda a função; o corpo roda a cada chamada |
| Chamada | nome(a1, a2) | argumentos vão para os parâmetros na mesma ordem |
| Retorno | return valor | encerra a função e devolve o valor; sem return, devolve None |
| Vários valores | return a, b | devolve uma tupla; desempacote com x, y = f() |
| Escopo | variável criada no corpo | é local: só existe durante a chamada |
| Lista como argumento | f(lista) | a função pode alterar a lista original |
| Valor padrão | def f(x, n=2): | padrões depois dos obrigatórios |
| Argumento nomeado | f(1, n=3) | posicionais primeiro, nomeados depois |
| Módulo | import math | funções prontas: math.sqrt(x) |
Qual será a saída?
Leia o código, escreva sua resposta e só então clique. Errou? Copie o código para o laboratório e execute.
Encontre o problema
Cada trecho tem (ou não) um problema. Descubra o que acontece ao executar antes de clicar.
Prática 1: primeiras funções
Complete a função no editor. O programa principal, no final do código, já lê a entrada e mostra o resultado: não precisa alterá-lo. ▶ Executar roda com a entrada que você quiser; ✓ Verificar roda os testes automáticos. Tente antes de abrir a solução!
1. Conversor de temperatura básico
Complete celsius_para_fahrenheit(c) para que ela devolva a temperatura em Fahrenheit: F = C × 9 / 5 + 32.
| Entrada | Saída esperada |
|---|---|
100 | 100.0 °C = 212.0 °F |
-40 | -40.0 °C = -40.0 °F |
Mostrar uma solução
2. O maior de três básico
Complete maior(a, b, c) para que ela devolva o maior dos três valores, sem usar max().
| Entrada | Saída esperada |
|---|---|
3 9 4 | Maior: 9 |
Os testes incluem números negativos e valores repetidos.
Mostrar uma solução
Prática 2: combinando funções
3. Média e situação intermediário
Complete as duas funções:
media(n1, n2, n3)devolve a média das três notas;situacao(m)devolve"aprovado"sem >= 7,"final"se4 <= m < 7e"reprovado"sem < 4.
| Entrada | Saída esperada |
|---|---|
5 6 4 | Média: 5.0 Situação: final |
Mostrar uma solução
4. Lendo uma nota válida intermediário
Complete ler_nota(mensagem): ela lê um número com input(mensagem) e, enquanto ele estiver fora do intervalo de 0 a 10, mostra Nota inválida e lê de novo. No fim, devolve a nota válida.
| Entrada | Saída esperada |
|---|---|
11 8 -1 6 | Nota inválida Nota inválida Média: 7.0 |
Repare: o programa principal chama a mesma função duas vezes, e a validação fica escrita uma vez só.
Mostrar uma solução
Prática 3: funções com laços e listas
5. Números primos desafio
Complete eh_primo(n): devolve True se n for primo e False caso contrário. Um número é primo quando é maior que 1 e só é divisível por 1 e por ele mesmo.
| Entrada | Saída esperada |
|---|---|
20 | 20 não é primo Primos até 20 : [2, 3, 5, 7, 11, 13, 17, 19] |
O programa principal usa sua função de dois jeitos: para responder sobre n e para montar a lista de primos até n.
Mostrar uma solução
6. Estatísticas de uma lista desafio
Complete estatisticas(numeros): recebe uma lista de inteiros e devolve três valores: o menor, o maior e a média. Não use min(), max() nem sum().
| Entrada | Saída esperada |
|---|---|
4 8 15 16 23 42 | Menor: 4 Maior: 42 Média: 18.00 |
Os testes incluem uma lista só com negativos: cuidado com o valor inicial do maior.
Mostrar uma solução
Laboratório livre
Espaço para testar ideias durante a aula. Sugestões: uma função fatorial(n) com for; uma função contar(texto, letra) sem usar count(); uma função tabuada(n, ate=10) com valor padrão.