Pular para o conteúdo

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.

FastMindAssistente de IA local

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
Baixar grátis para Windows

Plano Essencial grátis para sempre

Anatomia de uma função

Um quadro de código com a função saudar definida por def, seguida de duas linhas de print recuadas e, mais abaixo, a chamada saudar com parênteses. Seis marcas numeradas apontam as partes: 1 a palavra def, 2 o nome saudar, 3 os parênteses vazios, 4 os dois pontos, 5 o corpo recuado e 6 a chamada. Abaixo do código, a saída mostra ola e bem-vindo. Uma faixa diz que definir guarda o bloco e chamar executa o bloco.
As seis partes de uma função: def, nome, parênteses, dois pontos, corpo e chamada.

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, no while e no for.
  • 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

Seis linhas de código numeradas: print de inicio, def aviso, o print recuado de dentro da função, print de depois do def, a chamada aviso com parênteses e print de depois da chamada. Círculos ao lado de cada linha mostram a ordem real de execução: 1, 2, 5, 3, 4 e 6. Setas ligam a chamada ao corpo da função e de volta. À direita, a saída mostra inicio, depois do def, dentro da funcao e depois da chamada.
O def só guarda o corpo. A chamada faz o programa saltar para ele e voltar.

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:

  1. Executou o print("inicio").
  2. Chegou ao def, guardou o corpo sob o nome aviso e seguiu em frente. Nenhuma linha do corpo rodou.
  3. Executou o print("depois do def").
  4. Chegou à chamada aviso(), saltou para o corpo e executou print("dentro da funcao").
  5. 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 defined

Na 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.

FastTeacherPara professores

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
Conhecer o FastTeacher

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

Dois quadros lado a lado. À esquerda, sem função, o mesmo bloco de quatro linhas com led.on, sleep, led.off e sleep aparece copiado três vezes, somando doze linhas, e trocar o tempo exige editar seis linhas em três lugares. À direita, com função, uma definição de piscar com as quatro linhas e três chamadas piscar somam oito linhas, e trocar o tempo exige editar duas linhas em um lugar. Uma faixa avisa que esquecer uma das seis edições não gera erro.
O mesmo programa sem função, com três cópias, e com uma função chamada três vezes.

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.2 por 0.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 given

O 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 given

O 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 syntax

O 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 callable

O 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.

Para praticar no PyPlaca

Trilhas

Lições

Fichas de componentes

FastTeacherPara professores

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
Conhecer o FastTeacher

Versão Community grátis · Windows

FastMindAssistente de IA local

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
Baixar grátis para Windows

Plano Essencial grátis para sempre

FastTeacherPara professores

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
Conhecer o FastTeacher

Versão Community grátis · Windows