Lógica de Programação

Funções em Python

Aula interativa Prof. Raul de Araújo Lima · Sistemas de Informação · UniCatólica

Python carregando…

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.
Antes de executar, pergunte à turma: para trocar a regra da média, quantas linhas mudam em cada versão?

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çãoRecebeDevolve
len(x)uma sequênciao tamanho
max(a, b)valoreso maior
round(x, 1)número e casasnúmero arredondado
input(msg)a perguntao texto digitado
int(texto)um textoo número inteiro
print(x)valoresnada (None): só mostra
len("abc") → 3max(4, 9) → 9round(2.567, 1) → 2.6
Hoje vamos criar nossas próprias funções, que se usam exatamente do mesmo jeito.

Definindo uma função

anatomia.pyestrutura de uma definição
def saudacao(nome):
    texto = "Olá, " + nome + "!"
    print(texto)
def→palavra que inicia a definição saudacao→nome da função (mesmas regras das variáveis) (nome)→parâmetros: os dados que a função recebe :→dois-pontos, como no if, for e while recuo→corpo: as linhas que pertencem à função
Sem os parênteses, 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.

Peça para a turma prever a ordem das mensagens do primeiro exemplo antes de executar.

Parâmetros e argumentos

TermoOnde apareceExemplo
parâmetrona definição: é uma variável da funçãodef area(base, altura):
argumentona chamada: é o valor enviadoarea(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.

A quantidade de argumentos precisa bater com a de parâmetros. A última linha do exemplo passa só um. O que acontece?

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.

Cada chamada começa do zero: na segunda chamada, 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.

ChamadaSaída
moldura("Python")
**********
* Python *
**********

Depois, chame a função para três palavras diferentes.

"*" * 5 → '*****'len("Python") → 6
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(3) → 6dobro(3) + dobro(4) → 14dobro(dobro(2)) → 8
Na última linha do exemplo, a chamada de dentro é resolvida primeiro: 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

Função sem 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.

Cuidado com caminhos sem 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.

17 // 5 → 317 % 5 → 2q, r = (3, 2) → q = 3, r = 2
A função também pode receber uma lista e devolver um resumo dela. Os parâmetros e o retorno podem ser de qualquer tipo.

Desafio: calculadora de IMC

  1. Crie calcular_imc(peso, altura), que devolve peso ÷ altura².
  2. Crie classificar_imc(imc), que devolve o texto da classificação.
  3. No programa principal, leia peso e altura, chame as duas funções e mostre o resultado com uma casa decimal.
IMCClassificação
menor que 18.5abaixo do peso
de 18.5 até menor que 25peso normal
de 25 até menor que 30sobrepeso
30 ou maisobesidade
Nenhuma das duas funções deve usar 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.

A última linha do primeiro exemplo tenta mostrar 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.

Boa prática: tudo o que a função precisa entra por parâmetro; tudo o que ela produz sai pelo return. (Existe a palavra 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.

Escolha de propósito: ou a função modifica a lista recebida e não devolve nada (como 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.

round(2.567) → 3round(2.567, 2) → 2.57
Parâmetros com valor padrão vêm depois dos parâmetros obrigatórios. 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).

Argumentos posicionais vêm primeiro e os nomeados depois: 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.

ChamadaDevolve
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'
round(3.456, 1) → 3.5f"{2.5:.2f}" → '2.50'

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.

media(notas) relatorio(nome, notas) programa principal executando agora; ao terminar, devolve para relatorio base da pilha
Uma função pode até chamar a si mesma. Esse é o tema da aula de Recursão, e a pilha de chamadas será a chave para entendê-la.

Organizando um programa

Um programa com funções costuma seguir este formato:

  1. Definições no topo, cada uma com um nome que diga o que ela faz (um verbo ajuda: calcular_, ler_, mostrar_).
  2. 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.

FormaComo chamar
import mathmath.sqrt(16)
from math import sqrtsqrt(16)
import randomrandom.randint(1, 6)
math.sqrt(16) → 4.0math.pi → 3.14159…random.randint(1, 6) → 1 a 6
Em um projeto real, as suas funções também podem ficar em um arquivo separado (por exemplo 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.

  1. media(n1, n2, n3) devolve a média.
  2. situacao(m) devolve "aprovado" ou "reprovado".
  3. 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

ConceitoSintaxeLembre
Definiçãodef nome(p1, p2):só guarda a função; o corpo roda a cada chamada
Chamadanome(a1, a2)argumentos vão para os parâmetros na mesma ordem
Retornoreturn valorencerra a função e devolve o valor; sem return, devolve None
Vários valoresreturn a, bdevolve uma tupla; desempacote com x, y = f()
Escopovariável criada no corpoé local: só existe durante a chamada
Lista como argumentof(lista)a função pode alterar a lista original
Valor padrãodef f(x, n=2):padrões depois dos obrigatórios
Argumento nomeadof(1, n=3)posicionais primeiro, nomeados depois
Móduloimport mathfunçõ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.

EntradaSaí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().

EntradaSaí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" se m >= 7, "final" se 4 <= m < 7 e "reprovado" se m < 4.
EntradaSaí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.

EntradaSaí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.

EntradaSaí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().

EntradaSaí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.