Capítulo 5 — Funções

Até agora, seus programas cresceram bastante: trabalham com variáveis, tomam decisões com if e repetindo tarefas com for e while. Mas, conforme os programas ficam mais longos, começamos a notar um problema incômodo: código repetido. Você escreve a mesma sequência de comandos várias vezes. E toda vez que quer mudar algo naquele pedaço de código, precisa mudar em todos os lugares.

As funções existem para resolver exatamente esse problema. Uma função é como uma receita: você define uma vez, "para fazer um bolo, misture farinha, ovo, leite...", e depois, toda vez que quer um bolo, você chama a receita em vez de repetir todos os passos. E se a receita mudar — "a gente vai usar chocolate agora" — você muda uma vez, e a mudança vale para todos os bolos que você fizer daqui em diante.

Neste capítulo, vamos aprender a criar nossas próprias funções e a usá-las para deixar nossos programas mais organizados, mais fáceis de manter e bem mais profissionais.


1. Por que criar funções?

O problema: repetição de código

Imagine que você quer desenhar vários quadrados com o Turtle em posições diferentes. Sem funções, seu código fica assim:

import turtle

t = turtle.Turtle()

# Desenha quadrado 1
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)

# Desenha quadrado 2 (aqui está o mesmo código de novo!)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)

# Desenha quadrado 3 (e de novo!)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)

turtle.done()

Que desperdício! O mesmo código se repete. Se você quisesse mudar o tamanho para 80 pixels, teria que mudar em três lugares. Se tivesse 100 quadrados, ficaria incontrolável.

A analogia: função como receita

Uma receita de bolo é perfeita como analogia:

Funções que já usamos

Na verdade, você já está usando funções o tempo todo! print(), input(), len(), range() — tudo isso são funções. O Python fornece essas funções prontas. Agora vamos aprender a criar as nossas.

# Todas essas são funções que já conhecemos:
print("Olá!")           # função print()
nome = input("Seu nome: ")  # função input()
tamanho = len("Python")     # função len()
for i in range(5):      # função range()
    print(i)

A diferença agora é que vamos escrever nossas próprias funções, feitas especialmente para o que a gente precisa.


2. Definindo funções com def

A palavra-chave def ("definir") é como você diz ao Python: "quero definir uma função". Vamos ver a sintaxe:

Sintaxe básica

def nome_da_funcao():
    # código que executa quando a função é chamada
    # precisa estar indentado (4 espaços)

Três coisas importantes:

  1. A palavra def começa a definição
  2. nome_da_funcao é o nome que você escolhe — pode ser qualquer coisa (mas tem regras: sem espaços, sem caracteres especiais)
  3. Os dois-pontos (:) marcam o início do bloco da função
  4. O código dentro da função precisa estar indentado (com 4 espaços)

Seu primeiro programa com função

def saudacao():
    print("Olá, bem-vindo!")
    print("Como vai?")

# Aqui a função foi DEFINIDA, mas ainda não foi EXECUTADA
# Para executar, você precisa chamar:

saudacao()  # primeira chamada
saudacao()  # segunda chamada — executa tudo de novo!
saudacao()  # terceira — mesmo resultado

Quando você escreve saudacao() com os parênteses, está chamando a função. O Python vai para dentro da função, executa tudo que está indentado, e volta.

A saída será:

Olá, bem-vindo!
Como vai?
Olá, bem-vindo!
Como vai?
Olá, bem-vindo!
Como vai?

Diferença entre definir e chamar

Observe bem a indentação:

def desenhaquadrado():
    t.forward(100)  # ← dentro da função (indentado)
    t.left(90)      # ← dentro da função
    t.forward(100)  # ← dentro da função
    t.left(90)      # ← dentro da função
    t.forward(100)  # ← dentro da função
    t.left(90)      # ← dentro da função
    t.forward(100)  # ← dentro da função
    t.left(90)      # ← dentro da função

desenhaquadrado()  # ← fora da função, chamando ela
desenhaquadrado()  # ← chama de novo

Linhas indentadas dentro da definição são parte da função. Linhas sem indentação estão fora — são o programa principal.

Um exemplo com Turtle

import turtle

t = turtle.Turtle()

def desenha_quadrado():
    t.forward(100)
    t.left(90)
    t.forward(100)
    t.left(90)
    t.forward(100)
    t.left(90)
    t.forward(100)
    t.left(90)

# Agora em vez de copiar-colar, você chama a função:
desenha_quadrado()  # Desenha um quadrado
t.forward(50)       # Anda um pouco
desenha_quadrado()  # Desenha outro quadrado
t.forward(50)       # Anda de novo
desenha_quadrado()  # Desenha mais um

turtle.done()

Muito melhor! E se você quiser mudar o tamanho do quadrado, muda uma vez dentro da função, e todos os três ficam com o novo tamanho.


3. Parâmetros e argumentos

O que é um parâmetro?

Até agora, nossas funções fazem sempre a mesma coisa. Mas e se quisermos que uma função faça coisas diferentes dependendo da situação? Para isso, usamos parâmetros.

Um parâmetro é uma variável que você declara na definição da função. Um argumento é o valor que você passa quando chama a função. A diferença é pequena, mas importante:

Função com um parâmetro

def saudacao(nome):  # 'nome' é o parâmetro
    print(f"Olá, {nome}!")
    print(f"Bem-vindo, {nome}!")

# Quando chama, passa um argumento:
saudacao("Ana")      # "Ana" é o argumento
saudacao("Bruno")    # "Bruno" é o argumento
saudacao("Carlos")   # "Carlos" é o argumento

A saída será:

Olá, Ana!
Bem-vindo, Ana!
Olá, Bruno!
Bem-vindo, Bruno!
Olá, Carlos!
Bem-vindo, Carlos!

O valor que você passa ("Ana", "Bruno", etc.) é automaticamente armazenado na variável nome enquanto a função executa. Depois a função termina, e a variável desaparece (veremos mais sobre isso quando falarmos de escopo).

Função com múltiplos parâmetros

Você pode ter quantos parâmetros quiser:

def saudacao_completa(nome, idade, cidade):
    print(f"Olá, {nome}!")
    print(f"Você tem {idade} anos e mora em {cidade}.")

saudacao_completa("Ana", 16, "São Paulo")
saudacao_completa("Bruno", 15, "Rio de Janeiro")

Saída:

Olá, Ana!
Você tem 16 anos e mora em São Paulo.
Olá, Bruno!
Você tem 15 anos e mora em Rio de Janeiro.

Atenção: a ordem importa! O primeiro argumento vai para o primeiro parâmetro, o segundo para o segundo, e assim por diante. Se você chamar saudacao_completa("São Paulo", "Ana", 16), os valores ficariam completamente bagunçados.

Exemplo prático: Turtle com parâmetros

import turtle

t = turtle.Turtle()

def desenha_quadrado(tamanho):
    # Desenha um quadrado de qualquer tamanho
    for i in range(4):
        t.forward(tamanho)
        t.left(90)

# Agora você pode desenhar quadrados de diferentes tamanhos:
desenha_quadrado(100)
t.forward(50)
desenha_quadrado(80)
t.forward(50)
desenha_quadrado(50)

turtle.done()

Repare que usamos um for dentro da função — isso é perfeitamente normal! E o tamanho é uma variável normal dentro da função, serve exatamente como qualquer outra.

Valores padrão (default)

Às vezes você quer que um parâmetro tenha um valor "padrão" — se o usuário não passar nada, usa aquele valor. Por exemplo:

def saudacao(nome, palavra="Olá"):
    print(f"{palavra}, {nome}!")

saudacao("Ana")                    # Usa "Olá" como padrão
saudacao("Bruno", "Oi")            # Muda para "Oi"
saudacao("Carlos", "Bom dia")      # Muda para "Bom dia"

Saída:

Olá, Ana!
Oi, Bruno!
Bom dia, Carlos!

O parâmetro com valor padrão é marcado com =. Se você passa um argumento, ele sobrescreve o padrão. Se não passa, usa o valor padrão.

Regra importante: parâmetros com valores padrão sempre vêm por último na lista de parâmetros. Você não pode ter um parâmetro obrigatório depois de um opcional:

# ERRADO — sintaxe inválida
def algo(a=10, b):
    print(a + b)

# CORRETO — opcional vem por último
def algo(b, a=10):
    print(a + b)

4. Retornando valores com return

Funções que retornam vs. funções que executam

Até agora, nossas funções executam algo (como imprimir ou desenhar), mas não nos devolvem nada. Tem funções do Python que fazem isso — por exemplo, len() não só executa, ela também retorna um valor que você pode guardar:

comprimento = len("Python")  # len() retorna um número que você guarda em 'comprimento'
print(comprimento)           # 6

Você pode fazer isso com suas próprias funções usando return.

Sintaxe e exemplo

def dobra(numero):
    resultado = numero * 2
    return resultado

resposta = dobra(5)  # dobra() executa, calcula, e RETORNA 10
print(resposta)      # 10

return é a palavra que diz: "função, sua tarefa acabou, aqui está o resultado que você deveria retornar". Quando uma função encontra return, ela para de executar e devolve o valor.

Exemplo prático: conversor de temperatura

def celsius_para_fahrenheit(celsius):
    fahrenheit = (celsius * 9/5) + 32
    return fahrenheit

# Usa o valor retornado:
temp_f = celsius_para_fahrenheit(25)
print(f"25°C = {temp_f}°F")  # 25°C = 77.0°F

temp_f_negativa = celsius_para_fahrenheit(-40)
print(f"-40°C = {temp_f_negativa}°F")  # -40°C = -40.0°F

Retornando múltiplos valores (tuplas)

Python permite que você retorne mais de um valor ao mesmo tempo usando uma tupla (vamos estudar tuplas e listas no capítulo 6, mas aqui é só uma introdução):

def dividi_nome(nome_completo):
    partes = nome_completo.split(" ")  # separa pelo espaço
    primeiro_nome = partes[0]
    ultimo_nome = partes[-1]
    return primeiro_nome, ultimo_nome

nome1, nome2 = dividi_nome("Ana Silva")
print(f"Primeiro: {nome1}, Último: {nome2}")  # Primeiro: Ana, Último: Silva

Quando você escreve return a, b, o Python retorna os dois valores juntos como uma tupla. E quando você recebe com x, y = funcao(), está "desempacotando" a tupla.


5. Escopo de variáveis (introdução)

Variáveis locais vs. globais

Uma coisa importante de entender é que as variáveis dentro de uma função pertencem àquela função. Quando a função termina, essas variáveis "desaparecem". Chamamos isso de variável local — local quer dizer "pertence apenas a este lugar".

def calcula_imposto(preco):
    imposto = preco * 0.1  # 'imposto' é uma variável LOCAL
    return imposto

resultado = calcula_imposto(100)
print(resultado)           # 10.0 — funciona!
print(imposto)             # ERRO! 'imposto' não existe fora da função

Se você tentar acessar imposto fora da função, o Python dará um erro dizendo que a variável não existe. Isso é na verdade uma coisa boa, porque evita confusão.

Compare com variáveis globais — variáveis que você define fora de qualquer função:

taxa = 0.1  # Variável GLOBAL — existe em todo o programa

def calcula_imposto(preco):
    return preco * taxa  # Pode acessar 'taxa' porque é global

print(calcula_imposto(100))  # 10.0

Aqui taxa é global, então a função consegue acessá-la.

Por que evitar variáveis globais

Parece fácil usar variáveis globais, mas é uma péssima prática. Imagine um programa grande:

# PROBLEMA — evite assim!
contador = 0

def incrementa():
    contador = contador + 1  # Quer usar 'contador' global
    return contador

print(incrementa())  # Erro!

Isso dá erro! Quando você escreve contador = contador + 1 dentro da função, Python entende que contador é uma variável local, não global. Mas então você tenta ler contador antes dela existir — erro!

A forma correta de fazer isso seria:

# CORRETO — passar como parâmetro e retornar
def incrementa(contador):
    contador = contador + 1
    return contador

valor = 0
valor = incrementa(valor)
print(valor)  # 1
valor = incrementa(valor)
print(valor)  # 2

Ou guardar o valor em uma variável e atualizar:

contador = 0

def incrementa():
    return contador + 1

contador = incrementa()
print(contador)  # 1

Regra prática: funções recebem dados através de parâmetros e devolvem resultados através de return. Evite usar variáveis globais. Deixa o código mais limpo, mais seguro e mais fácil de entender.


6. Prática com Turtle e funções

Agora vamos combinar funções com Turtle para criar desenhos bem legais!

6.1. Função desenha_quadrado com parâmetros

import turtle

t = turtle.Turtle()
t.speed(5)

def desenha_quadrado(tamanho, cor):
    t.color(cor)
    for i in range(4):
        t.forward(tamanho)
        t.left(90)

# Desenha vários quadrados de tamanhos e cores diferentes
desenha_quadrado(100, "red")
t.forward(120)
desenha_quadrado(80, "blue")
t.forward(100)
desenha_quadrado(60, "green")

turtle.done()

6.2. Função desenha_triangulo

import turtle

t = turtle.Turtle()
t.speed(5)

def desenha_triangulo(tamanho, cor):
    t.color(cor)
    for i in range(3):
        t.forward(tamanho)
        t.left(120)  # ângulo externo do triângulo é 120°

desenha_triangulo(100, "purple")
t.forward(120)
desenha_triangulo(80, "orange")

turtle.done()

6.3. Função desenha_casa (combinando outras funções)

import turtle

t = turtle.Turtle()
t.speed(5)

def desenha_quadrado(tamanho, cor):
    t.color(cor)
    for i in range(4):
        t.forward(tamanho)
        t.left(90)

def desenha_triangulo(tamanho, cor):
    t.color(cor)
    for i in range(3):
        t.forward(tamanho)
        t.left(120)

def desenha_casa(tamanho_base, cor_parede, cor_telhado):
    # Paredes (quadrado)
    desenha_quadrado(tamanho_base, cor_parede)

    # Repositiona para desenhar o telhado
    t.penup()
    t.goto(t.xcor(), t.ycor() + tamanho_base)
    t.pendown()

    # Telhado (triângulo)
    desenha_triangulo(tamanho_base, cor_telhado)

# Desenha uma casa
desenha_casa(100, "brown", "red")

turtle.done()

6.4. Criando uma vila com a função

import turtle

t = turtle.Turtle()
t.speed(5)

def desenha_quadrado(tamanho, cor):
    t.color(cor)
    for i in range(4):
        t.forward(tamanho)
        t.left(90)

def desenha_triangulo(tamanho, cor):
    t.color(cor)
    for i in range(3):
        t.forward(tamanho)
        t.left(120)

def desenha_casa(tamanho_base, cor_parede, cor_telhado):
    desenha_quadrado(tamanho_base, cor_parede)
    t.penup()
    t.goto(t.xcor(), t.ycor() + tamanho_base)
    t.pendown()
    desenha_triangulo(tamanho_base, cor_telhado)

# Desenha várias casas em posições diferentes
for i in range(3):
    desenha_casa(60, "brown", "red")
    t.penup()
    t.forward(100)
    t.pendown()

turtle.done()

6.5. Função desenha_flor com pétalas

import turtle

t = turtle.Turtle()
t.speed(5)

def desenha_circulo(raio, cor):
    t.color(cor)
    t.begin_fill()
    t.circle(raio)
    t.end_fill()

def desenha_flor(raio_petal, numero_petalas, cor_petal, cor_centro):
    # Desenha as pétalas em volta
    angulo_entre_petalas = 360 / numero_petalas

    for i in range(numero_petalas):
        desenha_circulo(raio_petal, cor_petal)
        t.penup()
        t.goto(0, 0)  # volta ao centro
        t.pendown()
        t.left(angulo_entre_petalas)  # rotaciona para a próxima pétala

    # Desenha o centro
    desenha_circulo(raio_petal // 2, cor_centro)

# Desenha uma flor com 6 pétalas
desenha_flor(30, 6, "pink", "yellow")

turtle.done()

7. Exercícios

a) Escreva uma função saudacao(nome) que recebe o nome de uma pessoa e retorna (com return) uma string de boas-vindas, tipo "Bem-vindo, Ana!". Teste chamando a função e imprimindo o resultado.

b) Crie duas funções: - area_retangulo(largura, altura) — retorna a área - perimetro_retangulo(largura, altura) — retorna o perímetro

Teste com um retângulo de 5 por 10 e exiba ambos os resultados.

c) Escreva uma função eh_par(numero) que retorna True se o número for par, False caso contrário. Teste com números de 1 a 20 e exiba quantos são pares.

d) Com o Turtle, crie uma função desenha_poligono(lados, tamanho, cor) que desenha um polígono regular de quantos lados você quiser. Dica: o ângulo externo é 360 / lados. Teste com triângulo, quadrado, pentágono e hexágono.

e) Escreva as funções celsius_para_fahrenheit(celsius) e fahrenheit_para_celsius(fahrenheit). Teste convertendo 0°C, 100°C e 32°F.

f) Crie uma função conta_vogais(texto) que recebe uma string e retorna quantas vogais (a, e, i, o, u) tem. Ignore maiúsculas/minúsculas. Teste com frases diferentes.

g) Com o Turtle, crie uma função desenha_estrela(pontas, tamanho, cor) que desenha uma estrela com o número de pontas que você quiser. Uma estrela de 5 pontas tem ângulo de 144° entre os vértices. Teste desenhando uma estrela de 5 e outra de 8 pontas.

h) Escreva uma função valida_senha(senha) que retorna True se a senha tem no mínimo 8 caracteres e contém pelo menos um número. Caso contrário, retorna False. Teste com várias senhas.

i) Com o Turtle, crie: - desenha_arvore(altura) — desenha uma árvore simples (tronco + copa) - desenha_sol() — desenha um sol amarelo

Depois crie uma paisagem chamando essas funções em posições diferentes.

j) Escreva uma função maior_de_tres(a, b, c) que retorna o maior dos três números sem usar a função max(). Teste com vários trios de números.


8. Desafio de capítulo: Gerador de senhas aleatórias

Crie um programa que gera senhas aleatórias conforme o usuário pedir. O programa deve:

  1. Definir uma função gera_senha(tamanho, usar_numeros=True, usar_simbolos=False) que:
  2. Retorna uma senha aleatória do tamanho desejado
  3. Se usar_numeros for True, inclui números (0-9)
  4. Se usar_simbolos for True, inclui símbolos (!@#$%&*)
  5. Sempre inclui letras (maiúsculas e minúsculas)
  6. Usa import random para escolher caracteres aleatoriamente

  7. Pedir ao usuário:

  8. O tamanho desejado da senha
  9. Se quer números (s/n)
  10. Se quer símbolos (s/n)

  11. Gerar 3 opções de senha conforme pedido

  12. Deixar o usuário copiar a que gostar mais

Exemplo de saída:

=== Gerador de Senhas ===
Qual tamanho? 12
Incluir números? (s/n) s
Incluir símbolos? (s/n) n

Opção 1: aBcD3efG9hIj
Opção 2: XyZ7mNoPq2Rs
Opção 3: tUvW5wxYz1Ab

Copie a senha que você gostou!

Dicas: - Crie uma string com todos os caracteres possíveis (letras + números + símbolos) - Use random.choice(string_de_caracteres) para escolher um caractere aleatório - Use um for para gerar tamanho caracteres e montar a senha - Teste gerando senhas com várias combinações de opções


Resumo do capítulo

Você aprendeu que:

No próximo capítulo (Estruturas de dados: Listas e Strings), você vai aprender a trabalhar com coleções de dados — múltiplos valores guardados em um único lugar. Isso vai deixar seus programas ainda mais poderosos!

Python