Fundamentos
Funções em Python: def, chamar e dividir para conquistar
Aprenda a criar funções em Python com def, chamar pelo nome, entender a ordem de execução e dividir um programa em partes pequenas.
Por Prof. Rodrigo Faustino · Atualizado em · 15 min de leitura
Uma função é um bloco de código com um nome. Você escreve o bloco uma vez, com def, e depois executa quando quiser chamando o nome seguido de parênteses. Definir e chamar são dois momentos diferentes: o def só guarda o bloco, e quem faz o bloco rodar é a chamada.
Este artigo abre o módulo de funções. Até aqui os programas da série eram uma sequência de linhas que rodavam de cima para baixo, com decisões e laços no caminho. Quando o programa cresce, essa fila de linhas vira um problema: o mesmo trecho aparece em três lugares, ninguém lembra para que servia o bloco do meio, e uma mudança simples exige caçar cópias. A função resolve os três ao mesmo tempo. Veremos como definir e chamar, em que ordem as coisas rodam, os erros que aparecem nas primeiras vezes e como usar funções para dividir um problema em partes pequenas, inclusive nos programas de ESP32.
Você já chama funções
Desde o primeiro artigo da série você usa funções sem ter definido nenhuma. O print("ola") é uma chamada: o nome print, os parênteses e, dentro deles, o que se quer mostrar. O mesmo vale para input(), int(), len() e range(). Alguém escreveu o bloco que mostra texto na tela, deu o nome print a ele, e você só chama.
Definir a sua própria função é fazer a mesma coisa do outro lado: você escreve o bloco e escolhe o nome. A diferença é só de quem escreveu. A forma de usar, nome e parênteses, é idêntica.
A IA que lembra da sua vida e mora no seu computador
- Memória de longo prazo com a fonte de cada resposta
- Funciona offline: seus dados ficam no seu PC
- Lê PDFs, slides, fotos e gravações de reunião
Plano Essencial grátis para sempre
Anatomia de uma função
A figura mostra a menor função útil. A primeira linha é o cabeçalho: a palavra def, o nome da função, um par de parênteses e os dois pontos. As linhas seguintes, com recuo de quatro espaços, formam o corpo. A chamada, saudar(), fica fora do corpo, na margem, porque é um comando do programa principal e não parte da função.
Cada peça tem uma função própria no cabeçalho:
defé a palavra reservada que avisa ao Python que vem uma definição. Não pode ser usada como nome de variável.- O nome segue as regras de qualquer nome de variável: letras, números e sublinhado, sem começar por número e sem espaços. O costume é usar minúsculas, com sublinhado entre as palavras, como em
ligar_ventilador. - Os parênteses guardam os parâmetros, que são os valores que a função recebe. Aqui estão vazios. O próximo artigo da série enche esse espaço.
- Os dois pontos abrem o corpo, do mesmo modo que no
if, nowhilee nofor. - O recuo marca o que pertence à função. A primeira linha de volta à margem encerra o corpo.
Definir e chamar
def saudar():
print("ola")
print("bem-vindo")
saudar()
saudar()
print("fim")A saída é ola, bem-vindo, ola, bem-vindo e fim. As duas primeiras linhas com recuo foram escritas uma vez, e a saudação apareceu duas vezes, porque saudar() foi chamada duas vezes. Uma terceira chamada seria uma terceira saudação, sem que o corpo fosse copiado.
Os parênteses da chamada são obrigatórios. Escrever só saudar, sem eles, não executa nada: o Python entende que você está se referindo à função como um objeto, e não que você quer rodá-la.
def piscar():
print("ligou")
print("desligou")
piscar
print("nada aconteceu")A saída é só nada aconteceu. A linha piscar sozinha não dá erro e não faz nada, o que a torna um dos erros mais silenciosos do módulo. Se você imprimir o nome sem os parênteses, o Python mostra o objeto função:
def aviso():
print("rodou")
print(aviso)
print(type(aviso))<function aviso at 0x3ffb0010>
<class 'function'>O número depois do at é o endereço da função na memória e muda de uma execução para outra. O que importa é o <function aviso ...>: se esta linha aparecer na sua saída, faltaram parênteses na chamada.
A ordem em que as coisas rodam
Esta é a parte mais importante do artigo, porque quebra o hábito de "ler de cima para baixo". O programa abaixo tem um print dentro da função, escrito antes de outro print, e mesmo assim a saída vem em outra ordem:
print("inicio")
def aviso():
print("dentro da funcao")
print("depois do def")
aviso()
print("depois da chamada")A saída é inicio, depois do def, dentro da funcao e depois da chamada. Em ordem de execução, o Python fez o seguinte:
- Executou o
print("inicio"). - Chegou ao
def, guardou o corpo sob o nomeavisoe seguiu em frente. Nenhuma linha do corpo rodou. - Executou o
print("depois do def"). - Chegou à chamada
aviso(), saltou para o corpo e executouprint("dentro da funcao"). - Terminado o corpo, voltou para o ponto da chamada e continuou na linha seguinte,
print("depois da chamada").
A figura numera as linhas na ordem real de execução: 1, 2, 5, 3, 4 e 6. O corpo, que está na linha 3 do texto, é o quinto passo. Por isso ler o código da esquerda para a direita e de cima para baixo mostra onde as funções estão, mas não a ordem em que rodam. Para isso é preciso seguir as chamadas, como o dedo faz quando o professor pede para acompanhar um programa no papel.
Uma consequência direta: a função precisa estar definida antes de ser chamada, no sentido de execução.
aviso()
def aviso():
print("rodou")Traceback (most recent call last):
File "main.py", line 1, in <module>
NameError: name 'aviso' isn't definedNa linha 1 o Python ainda não passou pelo def, então o nome aviso não existe. A mensagem do computador é a mesma com uma diferença de texto, is not defined. Já o contrário é permitido: uma função pode chamar outra que foi escrita mais abaixo, desde que as duas estejam definidas quando a chamada acontecer.
def a():
b()
def b():
print("b rodou")
a()A saída é b rodou. Quando o a() roda, na última linha, o def b já foi executado. Se a chamada a() estivesse antes do def b, o erro seria o mesmo de cima, só que dentro da função a.
Da ementa ao semestre planejado
- Plano de ensino e calendário montados sozinhos
- Diário de aulas pronto para colar no SIGA
- Slides e listas de exercícios com gabarito
Versão Community grátis · Windows
Uma função chamando outra
O corpo de uma função pode chamar outras funções, e cada uma só termina depois de a seguinte terminar. A saída mostra o encaixe:
def a():
print("a comeca")
b()
print("a termina")
def b():
print("b comeca")
c()
print("b termina")
def c():
print("c roda")
a()A saída é a comeca, b comeca, c roda, b termina e a termina. A função a chamou b, que chamou c. O c terminou primeiro, depois o b, e por último o a: a última chamada a começar é a primeira a terminar. Essa ideia de "chamadas encaixadas" volta no artigo sobre recursividade, em que uma função chama a si mesma.
Em programas reais isto aparece o tempo todo. Uma função mostrar_relatorio chama titulo, que chama linha, e cada uma cuida de uma parte pequena:
def linha():
print("-" * 20)
def titulo(texto):
linha()
print(texto)
linha()
titulo("Relatorio")
print("dados aqui")
titulo("Fim")A saída são duas faixas de 20 hifens em volta de Relatorio, a linha dados aqui e outra faixa com Fim. Repare que titulo(texto) já tem um valor entre parênteses: é um parâmetro, o texto que a chamada passa para dentro da função. O artigo 17 explica isso por inteiro. Por enquanto, leia assim: "desenhe a linha, escreva o texto que eu mandei, desenhe a linha".
Por que usar funções
A figura compara o mesmo programa de duas formas. Pisque um LED três vezes, sem função, e o bloco led.on(), espera, led.off(), espera aparece três vezes. Com função, o bloco existe uma vez, e o programa chama o nome três vezes. Em código para a ESP32, a versão com função fica assim:
from machine import Pin
import time
led = Pin(2, Pin.OUT)
def piscar():
led.on()
time.sleep(0.2)
led.off()
time.sleep(0.2)
print("tres piscadas")
piscar()
piscar()
piscar()
print("fim")O texto no Serial é tres piscadas e fim, e o LED do GPIO2 pisca três vezes no circuito do simulador. A função usa a variável led, que foi criada fora dela. Ler uma variável de fora funciona sem nenhuma preparação. As regras para alterar essas variáveis ficam para o artigo sobre escopo.
Os ganhos de usar funções são quatro, e todos aparecem nesse exemplo:
- Menos repetição. O bloco de quatro linhas existe em um lugar só.
- Uma mudança em um lugar. Trocar
0.2por0.5é editar duas linhas, e não seis. A figura mostra o pior caso da cópia: esquecer uma das seis edições não gera erro, e a terceira piscada fica diferente das outras sem aviso nenhum. - Um nome que explica.
piscar()diz o que acontece, e quem lê o programa principal não precisa entender como o LED é ligado. - Teste em partes. Você chama a função sozinha, confere se ela funciona e só então a usa no resto do programa.
Uma função também não precisa ser chamada várias vezes para valer a pena. Uma função chamada uma vez só, com um bom nome, já separa o "o quê" do "como", e é muitas vezes o motivo de o programa ficar legível.
Dividir para conquistar
A expressão do título é um método. Um problema grande vira vários problemas pequenos, cada um resolvido por uma função, e o programa principal vira uma lista de chamadas que se lê como uma receita. O exemplo abaixo é um menu de três opções, no estilo do artigo sobre escolha entre muitas opções, em que cada ação ficou numa função:
def ligar():
print("ventilador ligado")
def desligar():
print("ventilador desligado")
def status():
print("ventilador em espera")
print("1 ligar, 2 desligar, 3 status")
op = input("opcao: ")
if op == "1":
ligar()
elif op == "2":
desligar()
elif op == "3":
status()
else:
print("opcao invalida")Com a resposta 2, a saída é o menu, opcao: 2 e ventilador desligado. O programa principal, do print do menu para baixo, cabe numa olhada e diz o que faz. Quando a ação de ligar crescer, com um relé, um registro de horário e uma mensagem de confirmação, só a função ligar muda. O if e o elif continuam como estão.
Um semáforo tem o mesmo desenho. Cada cor é uma função, e o laço só chama as três na ordem:
def vermelho():
print("vermelho 3s")
def amarelo():
print("amarelo 1s")
def verde():
print("verde 3s")
for ciclo in range(2):
print("ciclo", ciclo + 1)
verde()
amarelo()
vermelho()A saída repete duas vezes a sequência verde 3s, amarelo 1s e vermelho 3s, cada rodada marcada por ciclo 1 e ciclo 2. O programa principal é o semáforo inteiro em cinco linhas. Na placa, os print dariam lugar ao acendimento dos LEDs e a time.sleep, e o laço não mudaria. O desafio Semáforo pede esse comportamento com três LEDs, e o SOS em código Morse pede funções (def) para o ponto e o traço.
Um critério prático para decidir onde cortar: se você precisa de um "e" para descrever o que a função faz ("lê a nota e calcula a média e mostra o resultado"), ela provavelmente deveria ser duas ou três. Uma boa função faz uma coisa, e o nome diz qual.
Erros comuns e como reconhecê-los
Os erros de função aparecem em dois grupos: os que o Python acusa e os que passam em silêncio. Os do primeiro grupo vêm com mensagem.
Número errado de argumentos
Chamar com mais ou menos valores do que a definição espera é um TypeError:
def saudar():
print("ola")
saudar("ana")Traceback (most recent call last):
File "main.py", line 4, in <module>
TypeError: function takes 0 positional arguments but 1 were givenO erro inverso, uma função que espera um valor e é chamada sem nenhum:
def saudar(nome):
print("ola", nome)
saudar()Traceback (most recent call last):
File "main.py", line 3, in <module>
TypeError: function takes 1 positional arguments but 0 were givenO Python do computador escreve a mensagem com o nome da função (saudar() takes 0 positional arguments but 1 was given), o que ajuda a achar o culpado. A do simulador, que imita o MicroPython, é mais econômica e diz só function. Olhe o número da linha, que aponta para a chamada.
Faltou dois pontos, recuo ou corpo
def saudar()
print("ola")Traceback (most recent call last):
File "main.py", line 1
SyntaxError: invalid syntaxO Python do computador é mais específico e diz SyntaxError: expected ':'. O mesmo vale para o corpo sem recuo e para uma função que só tem comentário. O Python do computador acusa IndentationError: expected an indented block after function definition, e o simulador responde com SyntaxError: invalid syntax. O sintoma é o mesmo nos dois: o programa nem começa. Quando um corpo ainda não tem código, o pass é o marcador que a sintaxe aceita:
def saudar():
pass
saudar()
print("pass ok")A saída é pass ok. A função existe, não faz nada, e pode ser preenchida depois.
Nome de função igual a nome de variável
Uma função é um nome como outro qualquer, e uma atribuição pode cobri-lo:
dobro = 5
print(dobro(3))Traceback (most recent call last):
File "main.py", line 2, in <module>
TypeError: 'int' object isn't callableO nome dobro passou a guardar o número 5, e chamar um número não faz sentido. O mesmo acontece quando se redefine uma função. A última definição vence, sem aviso:
def f():
print("a")
def f():
print("b")
f()A saída é só b. Com dois def de mesmo nome em um arquivo longo, a primeira versão desaparece. Quando uma alteração "não faz efeito", procure uma segunda definição do mesmo nome mais abaixo.
Em sala de aula: onde as funções costumam tropeçar
Estes casos se repetem nas turmas. Em quase todos, o programa roda sem erro.
Definir a função e nunca chamar
O aluno escreve o def, clica em executar e nada acontece. A saída fica vazia, e a conclusão é que o computador "não funcionou". O corpo de uma função só roda quando alguém chama, e o def sozinho não chama. A pergunta de conferência: em que linha desta função eu escrevi o nome com parênteses?
Esquecer os parênteses na chamada
É o caso do piscar sozinho em uma linha. Também não dá erro. Quando a saída mostra <function ... at 0x...>, o problema é o mesmo, só que dentro de um print.
Chamar antes de definir
O programa está todo certo, mas a chamada foi escrita no topo e o def embaixo. O erro, NameError, é claro, e o conserto é mover a definição para cima da primeira chamada. Quando a chamada acontece dentro de outra função, a ordem de escrita deixa de importar, como o exemplo de a e b mostrou.
A função que faz tudo
Para "usar função" sem entender para quê, o aluno põe o programa inteiro dentro de uma só, def main():, e chama no fim. Roda, mas ele não ganhou nada: nenhum bloco ficou reutilizável, e o nome não diz nada. A pergunta é quantas coisas a função faz. Se a resposta for "tudo", divida.
Copiar a função em vez de chamar de novo
Aparecem piscar1, piscar2 e piscar3, com o mesmo corpo. A função existe justamente para evitar isso: um piscar chamado três vezes.
Mostrar na tela o que devia ser devolvido
Uma função que faz uma conta e usa print dentro dela resolve o exercício do momento, mas não deixa usar o resultado em outra conta. Isso fica claro quando o aluno tenta somar dois resultados e descobre que a função "devolve" None:
def dobro(n):
return n * 2
print(dobro(4))
print(dobro(dobro(4)))
x = dobro(5)
print(x)
def sem_retorno():
print("so imprime")
r = sem_retorno()
print(r)A saída é 8, 16, 10, so imprime e None. A função dobro devolve o valor com return, e o valor pode ser usado em outra chamada ou guardado numa variável. A sem_retorno só imprime, e o que ela entrega ao programa é None, o valor que significa "nada". O return é o assunto de um artigo inteiro, o 18. Aqui basta ver que existem duas coisas distintas: o que a função mostra e o que ela devolve.
Exercício: SOS com funções
Escreva um programa que monte o sinal SOS em Morse com funções. Três pontos, três traços e três pontos, separados por espaços. Crie ponto() e traco() que escrevem um sinal cada, espaco() que escreve um espaço, e as funções letra_s() e letra_o(), que chamam as anteriores. O programa principal só chama as letras.
def ponto():
print(".", end="")
def traco():
print("-", end="")
def espaco():
print(" ", end="")
def letra_s():
ponto()
ponto()
ponto()
def letra_o():
traco()
traco()
traco()
letra_s()
espaco()
letra_o()
espaco()
letra_s()
print()
print("fim")A saída é ... --- ... e fim. O end="" impede que o print pule de linha a cada sinal, e o print() solitário, depois da última letra, fecha a linha. Observe que letra_s e letra_o usam funções que o programa principal nem precisa conhecer, e que o principal tem sete linhas legíveis. Para melhorar, troque os três pontos repetidos por um for dentro de letra_s, e depois pense em como deixaria a quantidade de sinais configurável. O próximo artigo mostra como.
Perguntas frequentes
Uma função precisa de parâmetros?
Não. A saudar() do começo não tem nenhum. Parâmetros servem para a função trabalhar com valores diferentes a cada chamada, e são o assunto do próximo artigo.
Posso definir a função depois de chamá-la no arquivo?
Só se a chamada acontecer depois de o def ter rodado. No topo do arquivo, uma chamada solta antes do def dá NameError. Dentro de outra função, a ordem de escrita não importa, desde que as duas estejam definidas quando a chamada for executada.
Qual é a diferença entre definir e chamar?
Definir é escrever o def e guardar o corpo sob um nome. Chamar é escrever o nome com parênteses, o que faz o corpo rodar. Pode-se definir sem nunca chamar, mas nunca se chama sem ter definido.
Quantas funções um programa pode ter?
Quantas forem necessárias. O limite prático é a memória do aparelho: na ESP32, ela é bem menor que a do computador, e cada função ocupa um pouco. Em programas didáticos, isso não aparece.
Dá para chamar uma função dentro de um laço?
Dá, e é um uso muito comum. O semáforo do artigo chama verde(), amarelo() e vermelho() dentro de um for. A função é um comando como outro qualquer e pode ficar dentro de if, while e for.
O que uma função devolve quando não tem return?
None, como mostrou o exemplo sem_retorno. É o valor que o Python usa para dizer "não há resultado".
Para continuar
Releia o artigo sobre o if/else e o dos laços: tudo que foi dito lá vale dentro de uma função. Se quiser praticar com hardware, o desafio SOS em código Morse pede funções para o ponto e o traço, e o Semáforo é um bom caso para separar uma função por cor. Os desafios Função Dobro e Função Triplo usam parâmetro e return, e ficam melhores depois dos próximos dois artigos. A trilha Lógica com Python reúne todos os desafios.
O próximo artigo trata dos parâmetros e argumentos: como passar valores para a função, em que ordem, como dar nomes às chamadas, como definir valores padrão e como aceitar uma quantidade qualquer de argumentos com *args.