6  Funções em Python - Reutilizando Código

6.1 O que você saberá se você ler todo este capítulo?

  1. Conceito de Funções: O que são funções e por que são fundamentais em programação
  2. Funções Built-in: Como usar funções que já vêm com Python (print(), input(), len(), etc.)
  3. Criando Funções: Como definir suas próprias funções com def
  4. Parâmetros e Retorno: Como passar dados para funções e receber resultados
  5. Tipos de Funções: Com/sem parâmetros, com/sem retorno
  6. Escopo de Variáveis: Onde as variáveis existem dentro e fora das funções
  7. Reutilização de Código: Como evitar repetição e organizar melhor seu programa
  8. Aplicações Práticas: Exemplos reais de quando e como usar funções

🎓 Vindo do Capítulo 5? Perfeito! Você já domina loops. Agora é hora de aprender a organizar seu código! Este capítulo ensina como criar blocos reutilizáveis de código.

🎯 Objetivo deste capítulo: Ao final, você será capaz de criar funções personalizadas, entender o conceito de reutilização de código e organizar programas de forma mais limpa e eficiente.

⚠️ Importante: Este capítulo é fundamental! Sem funções, você teria que repetir código infinitamente. Aqui você aprende a criar “receitas” reutilizáveis!

6.2 De uma Receita para um Livro de Receitas

Até o momento conectei conceitos de algoritmos com receitas de bolo. Vamos continuar assim, mas agora vamos avançar mais um passo em complexidade. Por isso, preste bastante atenção nas explicações, beleza?

Imagem contendo vários doces do tipo brigadeiro.

Pensemos que a sua receita de bolo fez muito sucesso e que, agora, você foi contratado para escrever um livro de várias receitas. Legal, né? Bom, vamos supor que você começou a trabalhar assim:

  1. Primeiro, você escreveu uma receita de bolo de chocolate, que é uma receita na qual você domina muito bem. Você descreveu os ingredientes, o modo de preparo e o resultado esperado.
  2. Depois, você escreveu uma receita de brownie. Você percebeu que um ou outro ingrediente também tinha na receita de bolo de chocolate, mas continuou escrevendo mesmo assim. Por isso, descreveu os ingredientes, modo de preparo, e o resultado esperado.
  3. Depois, você fez a mesma coisa com uma torta de limão, um bolo de cenoura, uma torta de maçã, uma torta holandesa, um bolo de baunilha com cobertura de chocolate, e assim sucessivamente.
  4. Na sua centésima receita, você estava de saco cheio: você percebeu que o processo de fazer os mesmos passos (descrever os ingredientes, modo de preparo e o resultado esperado) era um processo chato.
  5. Pior: como você se cansou, percebeu que aquelas receitas que você fez durante o final de noite ou na madrugada tinham algumas pequenas falhas porque você esqueceu de copiar e colar alguma instrução de outra receita. Como o processo era tão mecânico (fazer 100 vezes coisas parecidas), isso acabou acontecendo algumas vezes.
  6. Você também percebeu que algumas coisas eram exatamente iguais entre as receitas. O passo-a-passo de como fazer a cobertura, por exemplo, era o mesmo texto copiado e colado umas vinte vezes entre diferentes receitas.
  7. Você quase teve um ataque de raiva quando percebeu que esse passo-a-passo de como fazer a cobertura tinha um erro de digitação. Por isso, você teve que olhar receita a receita para corrigir isso, e pelo menos vinte vezes.

Por isso, você teve o seguinte pensamento: > 💭 Puxa, seria legal se tivesse um jeito de escrever lá no começo do livro algo como “Instruções para fazer a cobertura”, e aí depois no livro e no meio das receitas eu só referenciaria a página contendo estas instruções quando precisasse.

Bom, em programação isto também é possível com o uso de funções. Vamos lá?

6.3 O que são Funções?

As funções são usadas em linguagem de programação (como o Python) para agrupar instruções que realizam uma determinada tarefa e que podem ser reutilizadas em diferentes partes do código. Elas permitem que você crie uma sequência de ações que podem ser executadas repetidamente sem precisar reescrever todo o código a cada vez que a tarefa precisa ser executada.

6.3.1 Analogia da Cobertura do Bolo

Por exemplo, imagine que você tenha que executar uma tarefa que envolve diversas etapas, como fazer a cobertura de um bolo (já falamos sobre isso, não é?). Cada etapa pode ser vista como uma função separada, como misturar os ingredientes, bater a massa, levar ao forno, etc. Ao criar funções separadas para cada uma dessas tarefas, você pode reutilizá-las em outras receitas de bolo sem precisar escrever as mesmas coisas novamente.

6.3.2 Analogia dos Blocos de Lego

Quer outra analogia? Vamos começar a tratar o seu código como sendo uma receita de bolo (isto é: uma sequência de passos) para vários blocos de Lego, onde cada bloco possui uma função específica. Você poderá trabalhar, organizar e encaixar os blocos como quiser.

6.3.3 Classificação das Funções

Em Python, podemos organizar as funções assim:

6.3.3.1 1. Quem criou a função?

  • Funções Built-in: Funções que já são inclusas no Python por padrão
  • Funções de Bibliotecas: Funções que outras empresas ou desenvolvedores fizeram, e que estão disponíveis para você usar
  • Suas Próprias Funções: Funções que você irá criar para o seu próprio código

6.3.3.2 2. Como podemos usar a função?

  • Função sem entrada e sem retorno
  • Função sem entrada e com retorno
  • Função com entrada e sem retorno
  • Função com entrada e com retorno

6.3.4 Refatoração

Ah, e antes que me esqueça: usar funções é uma das maneiras de melhorarmos o código pela refatoração.

💡 Refatoração é importante porque torna o código mais limpo, fácil de entender e manter, evitando problemas como bugs e falhas no sistema, além de facilitar a adição de novas funcionalidades. A refatoração pode envolver a modificação de nomes de variáveis, extração de trechos de código em funções separadas, eliminação de código redundante, melhoria do desempenho e otimização do código em geral.

6.4 Vou te contar um segredo à meia-noite

E se eu te disser que você já está usando funções? Veja o código abaixo:

# Solicita que o usuário digite um número em formato de string
num_string = input("Digite um número: ")

# Converte a string para um número de ponto flutuante (float)
num_float = float(num_string)

# Formata o número em uma string com duas casas decimais
num_formatado = "{:.2f}".format(num_float)

# Imprime o número formatado na tela
print("O número digitado foi: {}".format(num_formatado))

É um código que pede para que um usuário digite um número com quantas casas decimais o usuário quiser e que, no final, mostra este número arredondado com duas casas decimais, certo? Agora, observe o seguinte: as palavras-chave input, float e print sempre estão com uma cor diferente, e sempre depois delas temos um abre-e-fecha parênteses. Curioso, né?

Agora, vamos voltar um passo:

  1. Percebe que input(), float() e print() sempre funcionam do mesmo jeito independentemente do código? Quer dizer: não importa se você está estudando loops, if/else ou qualquer outra coisa.
    • Se você chama no seu código um print(), a sua expectativa é a de que uma mensagem seja mostrada ao usuário, não é? Você não sabe que mágica existe dentro deste print() e nem como ele funciona: é uma caixa-preta em que você só dá um texto para ele e, como resultado, aquilo é mostrado na tela, né?
    • A mesma coisa é o input(): como o Python se conecta ao seu sistema operacional e ao seu teclado para ler o que o usuário digita? Como ele traduz o movimento de uma pessoa de apertar um botão para um texto que aparece na tela e dentro do Python? É uma outra caixa-preta: não sabemos como, mas sabemos que tem uma entrada esperada (uma mensagem que você pode querer mostrar ao usuário) e uma saída esperada (um texto que o usuário digitou).
    • O float(), a mesma coisa: ele faz outra mágica dentro de outra caixa-preta em que a entrada é um texto e a saída é aquele texto convertido em um número decimal.
  2. A mesma lógica de caixa-preta é usada pelo format. Ele também possui um abre-e-fecha parênteses. Ele não tem uma cor diferente, mas é porque ele está sendo chamado de uma forma diferente depois da string (sempre a sintaxe é "texto entre aspas duplas" seguido de .format()). Ele é chamado desse jeito (depois de uma string) porque ele atua sobre um objeto do tipo str (ou seja, uma string). O nome bonito para funções assim é métodos, mas veremos mais sobre isso depois.
  3. Veja que funções assim (e outras que você também já viu, como int(), range() e str()) sempre seguem alguns padrões:
    • As funções sempre são seguidas por um abre-e-fecha parênteses (como range(10) e print("Oi")).
    • As funções sempre fazem alguma ação. “Chamamos” o print() para mostrar algo na tela. “Chamamos” o input() para ler algo que o usuário digitou. “Chamamos” o int() para converter um número que está em formato de texto para um inteiro.
    • Se as variáveis são como os ingredientes de uma receita de bolo, as funções são como pequenas receitas (ou passo-a-passo) que repetiremos algumas vezes ao longo do caminho. São, de certa forma, pequenos algoritmos.

6.5 Funções que já vêm de brinde para você

Quer outro segredo? Saber ler documentações é o que te trará uma boa vantagem competitiva para o futuro. É neste sentido que eu te apresento a documentação oficial do Python.

6.5.1 A Importância da Documentação

Ler a documentação oficial de um software é uma habilidade essencial para programadores iniciantes e experientes. A documentação descreve o propósito e a funcionalidade de cada elemento de um código, tornando mais fácil entender como usá-lo e solucionar possíveis erros. Além disso, a documentação oficial também inclui exemplos e amostras de código que podem ser utilizados como modelos para soluções específicas.

💡 Dica: Saber ler e interpretar estas documentações também é um jeito bem legal de aprender boas práticas de programação e descobrir recursos ocultos que podem simplificar tarefas complexas. Os desenvolvedores de bibliotecas e linguagens de programação trabalham continuamente para atualizar suas documentações com novas funcionalidades e recursos, portanto, manter-se atualizado sobre as novidades pode aprimorar a sua capacidade de auto-desenvolvimento.

6.5.2 Built-in Functions

A documentação oficial é uma fonte de informação confiável e essencial para as pessoas de todos os níveis de habilidade e experiência. É bem mais confiável do que este livro que você está lendo, bem mais confiável do que qualquer outro livro e curso pela internet também. Afinal de contas, é a fonte oficial e que é atualizada sempre.

Bom - voltando ao link que eu coloquei acima. Você pode ver que é uma página com as funções que já vem por padrão no Python. Como elas já vem inclusas, o nome em inglês para isso é built-in functions. Você verá que além do print(), input(), format(), range(), int(), float() e str() existem várias outras como, por exemplo:

6.5.2.1 Funções Matemáticas

  • abs(): Calcula o valor absoluto de um número. Teste abs(-50.4), por exemplo.
  • pow(): Você poderá calcular exponenciais. Vamos supor que você queira calcular \(34^5\) em Python. Uma alternativa seria fazer 34 ** 5. Outra seria fazer pow(34, 5).
  • round(): Arredonda um número para a quantidade de casas pré-determinadas (segundo parâmetro). Se você não informar um segundo parâmetro, ele arrendondará para um número inteiro. Teste round(90.5949) e veja a diferença para round(90.5949, 1), round(90.5949, 3) e round(90.5949, 10), por exemplo.

6.5.2.2 Funções de Sequências

  • len(): Calcula a quantidade de caracteres em uma string ou o total de elementos de uma sequência de valores. Teste len([5, 900, 1, -2]), por exemplo.
  • max(): Calcula o maior valor que existe em uma sequência de valores. Teste max([5, 900, 1, -2]), por exemplo.
  • min(): Calcula o menor valor que existe em uma sequência de valores. Teste min([5, 900, 1, -2]), por exemplo.
  • sum(): Calcula a soma total de uma sequência de valores. Teste sum([5, 900, 1, -2]), por exemplo.
  • sorted(): Serve para ordenar os elementos de uma sequência, do menor para o maior.
  • reversed(): Serve para reverter a ordem de uma sequência. Se você fizer reversed([5, 900, 1, -2]) você terá um iterador para ver esses itens de trás pra frente.
    • Iterador: é um iterador é como se fosse uma “lista inteligente” que o programa usa para acessar uma série de valores. Como uma analogia, vamos supor que você tem uma caixa cheia de doces, mas não pode ver tudo o que tem dentro dessa caixa de uma vez só. O iterador seria como a sua mão, que pode pegar um doce de cada vez e mostrar para você.

6.5.2.3 Funções de Arquivos

  • open(): Serve para abrir arquivos. Veremos isso em breve, mas você poderá usar essa função para ler o conteúdo de arquivos como textos, músicas e imagens.

Ah, um comentário sobre o reversed() (isso também se aplica ao range()): algumas funções retornam iteradores. Veja o código abaixo e, logo em seguida, os resultados:

elementos = [5, 900, 1, -2]
print(f'Os elementos invertidos são {reversed(elementos)}.')
print(f'Os elementos invertidos são {list(reversed(elementos))}.')
print(f'Os elementos ordenados são {sorted(elementos)}.')

print('\nUsando loop para mostrar os elementos invertidos:')
for i in reversed(elementos):
    print(i)

print('\nUsando loop para mostrar os elementos ordenados:')
for i in sorted(elementos):
    print(i)
Os elementos invertidos são <list_reverseiterator object at 0x000002107ABA7490>.
Os elementos invertidos são [-2, 1, 900, 5].
Os elementos ordenados são [-2, 1, 5, 900].

Usando loop para mostrar os elementos invertidos:
-2
1
900
5

Usando loop para mostrar os elementos ordenados:
-2
1
5
900

Veja que o primeiro resultado do print() não foi a sequência de elementos, mas sim um <list_reverseiterator object>. Pensando na analogia da mão da caixa de doces, esta é a mão. Para ver o que tem dentro desta sequência invertida é possível usar a função list(), que converte para uma sequência do tipo lista. Veja que o segundo print() já deu o resultado esperado. Trouxe isto para você porque você pode ver alguma coisa assim quando estiver testando algumas funções como o range() ou reversed().

6.5.3 Outras funções

Também existem outras funções que também já existem no Python como, por exemplo:

E, além disso, existem bibliotecas feitas por outras pessoas e empresas com funções específicas como, por exemplo:

Assim que você tiver mais experiência em Python você naturalmente começará a usar esses módulos e bibliotecas extras para criar algoritmos mais complexos. Compartilho isso aqui para que você saiba a direção que você seguirá, mas antes disso é legal que você saiba como criar as suas próprias funções. Vamos lá?

6.6 Criando a sua própria função

Para criar uma função em Python, basta usar a palavra-chave def, seguida pelo nome da função que explique de forma simples o que ela faz e, depois, o código. Por exemplo:

def saudar_usuario():
    print("Olá! Tudo bem por aí?")

6.6.1 Analisando a Estrutura

Veja a estrutura: primeiro, defini a função com a palavra-chave def (entendeu? Definir -> def). Depois que defini a função, dei um nome que mostrasse o que ela deve fazer. Este nome não pode ter acentos ou espaços, e deve sempre estar em minúsculas. Se for usar mais de uma palavra, separe-as com underscores (_). Depois, continuei com um abre-e-fecha parênteses (toda função tem isso, e vamos explorar isso em seguida) e os dois-pontos. Esses dois-pontos servem para que o Python entenda que logo depois disso teremos o código de dentro da função. No caso, somente mostraríamos uma mensagem para o usuário chamada “Olá! Tudo bem por aí?”.

6.6.2 Chamando a Função

Agora, o que acontece se você chamar esta função cinco vezes?

saudar_usuario()
saudar_usuario()
saudar_usuario()
saudar_usuario()
saudar_usuario()

A resposta é simples: a lógica da função será executada cinco vezes. Neste caso, significa que a mensagem será mostrada cinco vezes na tela.

6.6.3 Regras para Nomes de Funções

  • Permitido: minha_funcao, calcular_media, verificar_idade
  • Não permitido: minha função, minha-função, MinhaFuncao
  • 💡 Dica: Use nomes descritivos que expliquem o que a função faz

6.6.4 Exemplo com Parâmetros e Retorno

Agora, teste este código:

def somar(a, b):
    resultado = a + b
    return resultado

soma = somar(2, 5)
print(soma)

soma = somar(5, 2)
print(soma)

soma = somar(1000, -20)
print(soma)

6.6.5 Como Funciona

Este código define uma função chamada somar, que recebe dois argumentos: a e b. Dentro da função, os argumentos são somados e o resultado é armazenado na variável resultado. Em seguida, a função retorna o valor de resultado.

💡 Lembra que o funcionamento de uma função é uma caixa-preta? Todo o resto do seu código não tem a mínima noção do que esta função (isto é, as três primeiras linhas do código acima) fazem.

6.6.6 Executando a Função

Fora da função, temos três chamadas à função somar() com diferentes valores de a e b:

  • Primeira chamada: a é igual a 2 e b é igual a 5, resultando em uma soma de 7
  • Segunda chamada: os valores de a e b são invertidos, mas ainda resultam em uma soma de 7
  • Terceira chamada: a é igual a 1000 e b é igual a -20, resultando em uma soma de 980

O resultado de cada chamada à função é armazenado na variável soma, que é impressa na tela usando a função print(). Assim, a saída do programa será:

7
7
980

6.6.7 Vantagens das Funções

Este exemplo ilustra como as funções podem ser usadas para reutilizar o código e simplificar a sua leitura e manutenção. Em vez de repetir o código da soma em cada uma das chamadas, podemos definir uma função para realizar a operação e chamá-la várias vezes com diferentes argumentos. Isso torna o código mais legível e fácil de modificar, se necessário.

Com isso, vamos pensar em algumas formas diferentes de construirmos funções:

6.6.8 Função com parâmetros e com retorno

O tipo de função mais comum é a que possui parâmetros (ou argumentos) de entrada e que retornam algo. Afinal, se falamos que uma função é como se fosse um pequeno pedaço de algoritmo e se também falamos que um algoritmo possui uma entrada e uma saída, a expectativa é a de que usemos as funções para produzir algo (uma saída) a partir de algo que entreguemos para a função (uma entrada).

6.6.8.1 Exemplo com fatorial

Teste o seguinte código:

def calcular_fatorial(numero):
    fatorial = 1
    for i in range(1, numero+1):
        fatorial *= i
        
    return fatorial

a = 5
resultado = calcular_fatorial(a)
print(resultado)

b = 3
resultado = calcular_fatorial(b)
print(resultado)

Nesse exemplo, a função recebe o argumento numero para calcular o fatorial. Este numero é um parâmetro de entrada que a função receberá para calcular o fatorial. Veja que este numero é usado somente dentro da função: em nenhum outro momento precisaríamos criar uma variável com este nome fora da função. O mesmo vale para a variável fatorial: ela só existe dentro da função. Ah, e no final, a função retrna o fatorial calculado como um único valor de retorno.

Uma prova disso é que ao chamarmos a função com calcular_fatorial(a) e calcular_fatorial(b) usamos as variáveis a e b, e nada de numero, não é? Então, vale uma informação importante:

💡 As variáveis e parâmetros que existem dentro de uma função nascem e morrem dentro dela, e não existem fora dela.

6.6.8.2 Um outro exemplo com dois parâmetros de entrada

A real é que é possível termos vários parâmetros de entrada. Imagine um caso em que precisemos calcular a área de um triângulo. Para tal, precisamos de dois parâmetros: base e altura. Teste a função abaixo:

def calcular_area_triangulo(base, altura):
    area = (base * altura) / 2
    return area

Neste exemplo, a função calcular_area_triangulo (percebe que esse nome é bem sugestivo?) recebe os argumentos base e altura para calcular a área de um triângulo. A função retorna a área calculada como um valor de retorno. Um teste dessa função seria:

resultado = calcular_area_triangulo(10, 5)
print(resultado)

Percebeu que em nenhum momento criamos as variáveis base, altura e area fora da função? Elas não existem em nenhum momento dessas duas linhas acima. Isto reforça o que falei anteriormente sobre as funções serem caixas-pretas para o código: as variáveis, funções e afins que acontecem dentro daquela função ficam dentro daquela função somente. Quer uma analogia? Vamos supor que você está fazendo um pedido para um restaurante. Você não sabe quantas pessoas trabalham na cozinha e nem quantas pessoas efetivamente fizeram o seu alimento. Você não sabe quanto tempo demorou, e nem a ordem que fizeram o preparo. Não sabe a marca dos ingredientes, também. Tudo o que você tem é o seu pedido como entrada (análogo a esses parâmetros de entrada) e o seu prato pronto como saída (análogo ao retorno).

6.6.8.3 E lá vem mais outro exemplo

E dá para combinar if/elif/else ou um for/while em uma função? É claro! Olha só:

def eh_par(numero):
    if numero % 2 == 0:
        par = True
    else:
        par = False
        
    return par

resultado = eh_par(10)
print(resultado)

Nesse exemplo, a função eh_par() (já que não posso usar acentos para chamar de é_par() recebe o argumento numero para verificar se este valor é par ou não. A função retorna True se o número é par e False caso contrário. Percebeu como tem um if e else na função?

Também poderíamos deixar o código ainda mais enxuto o reescrevendo assim:

def eh_par(numero):
    if numero % 2 == 0:
        return True
    else:
        return False

resultado = eh_par(10)
print(resultado)

Esse código faz exatamente a mesma coisa do exemplo anterior. A diferença é que coloquei o return (que retorna de volta um valor ao algoritmo principal) para estar dentro do if e do else. Assim, não precisaria mais daquela variável par. Como uma analogia, imagine um fast-food com drive-thru: você pode retirar a sua comida em dois lugares diferentes - tanto na janelinha que é disponível para pessoas que fazem os pedidos dentro de um carro, tanto no balcão dentro do restaurante.

6.6.8.4 Um outro exemplo retornando dois valores

Tá, e se eu quisesse retornar mais de um valor ao mesmo tempo? Digamos que eu queira modificar aquela função que calcula a área de um triângulo para também retornar a área de um retângulo. Como seria? Simples!

def calcular_areas(base, altura):
    area_triangulo = (base * altura) / 2
    area_retangulo = base * altura
    return area_triangulo, area_retangulo

triangulo, retangulo = calcular_areas(10, 5)
print(f'A área do retângulo é {retangulo}')
print(f'A área do triângulo é {triangulo}')

Consegue perceber que agora a nossa função calcular_area_triangulo foi modificada para se tornar calcular_areas? Agora, o return possui dois valores: o primeiro é a área do triângulo. Depois, a área do retângulo. Veja também que a antepenúltima linha do código armazena esses dois valores em duas variáveis chamadas triangulo e retangulo. Cada uma delas armazenará um dos dois valores do return seguindo a mesma ordem.

O que acha de modificar esta função para ter um terceiro ou quarto return?

6.6.9 Função sem parâmetros e com retorno

Agora, não é obrigatório usarmos os parâmetros de entrada em cada função. Veja só:

def mostrar_nome_idade_exemplo():
    return "Fulano de Tal", 42
    
nome, idade = mostrar_nome_idade_exemplo()

Esta seria uma função que retorna um exemplo de nome e idade. Veja que não precisamos dar nenhum parâmetro de entrada: depois do def e do nome da função, temos os parênteses abrindo e fechando sem nada dentro. Isto significa que a função não precisa de nada externo para funcionar: ela retorna um nome e idade de exemplo para você sempre que precisar, e ela é “independente” para fazer isto.

6.6.10 Função com parâmetros e sem retorno

Da mesma forma, o return também não é obrigatório para cada função. Veja só:

def eh_par(numero):
    if numero % 2 == 0:
        print(numero, "é um número par")
    else:
        print(numero, "não é um número par")
        
eh_par(10)

Perceba que adaptamos aquela função eh_par para não retornar nada. No lugar, ela somente mostrará algo na tela com o print(). Nesses casos em que não há um return poderemos chamar a função de forma direta. Lembra que antes precisávamos ter uma linha chamada resultado = eh_par(10) para poder guardar o resultado em uma variável? No exemplo acima, isto não é mais necessário.

Isto posto, é importante que você saiba que o mais comum é usarmos um return. Imagine o seguinte: e se quiséssemos usar o resultado dessa função em um if? Ou, e se quiséssemos montar uma frase diferente na tela? Nestes casos, a falta de um return não permitiria cenários desse tipo. Como uma analogia, a função é um restaurante. Você faz o seu pedido no restaurante e só pode comer dentro do restaurante e seguindo todas as regras de lá. Pegar o que restou para comer em casa? Não pode. Pedir para delivery? Esquece. Só pode comer de um jeito, e é do jeito deles, e não o seu.

6.6.11 Função sem parâmetros e sem retorno

É bem difícil termos funções assim. É como se fosse um restaurante em que servem só um único prato e de um único jeito. Sem adaptações, e sem espaço para discussão. E, ainda, só pode comer lá dentro. Existe um caso útil para funções assim: mostrar menus na tela:

def mostrar_menu():
    print("Olá! Digite uma opção do menu. Em seguida, aperte Enter.")
    print("1 - Listar todos os cadastros.")
    print("2 - Fazer um novo cadastro.")
    print("3 - Remover um cadastro já existente.")
    print("4 - Modificar um cadastro já existente.")
    print("9 - Ajuda.")
    print("0 - Sair.")
    
mostrar_menu()

Veja que o código acima não possui nenhuma interação: não tem nenhum parâmetro de entrada e, por isso, esta função sempre mostrará as mesmas mensagens do mesmo jeito e na mesma ordenação. Também não retorna nada: não interage com o usuário e não cria nenhum valor que seria útil para manipular no algoritmo. Só mostra mensagens, e é isso.

6.7 Refatoração: Melhorando Código Existente

Agora que você já sabe criar e usar funções, vamos falar sobre uma das aplicações mais importantes delas: a refatoração.

6.7.1 O que é Refatoração?

Refatoração é o processo de melhorar a estrutura interna do código sem alterar seu comportamento externo. É como reorganizar uma cozinha: você não muda o que cozinha, mas torna o processo mais eficiente e organizado.

6.7.2 Por que Refatorar é Importante?

Imagine que você escreveu um programa que funciona, mas está difícil de entender ou modificar. Talvez você tenha: - Código repetido em vários lugares - Nomes de variáveis confusos como x, temp, dados - Funções muito grandes que fazem muitas coisas - Números “mágicos” espalhados pelo código (como 3.14 sem explicação)

💡 Refatorar torna o código mais limpo, fácil de entender e manter, evitando problemas como bugs e falhas no sistema, além de facilitar a adição de novas funcionalidades.

6.7.3 Quando Refatorar?

  • Quando você encontra código duplicado - se você está copiando e colando código, é hora de criar uma função
  • Quando o código está difícil de entender - se você precisa ler várias vezes para entender, precisa ser melhorado
  • Quando você precisa adicionar uma nova funcionalidade - código bem organizado é mais fácil de estender
  • Quando você encontra bugs - código limpo tem menos chances de ter erros

6.7.4 Técnicas de Refatoração que Vamos Aprender

  1. Extrair Funções - Transformar código repetido em funções reutilizáveis
  2. Melhorar Nomes - Usar nomes descritivos para variáveis e funções
  3. Eliminar Código Duplicado - Identificar e remover repetições
  4. Reduzir Complexidade - Quebrar funções grandes em funções menores
  5. Adicionar Validações - Melhorar a robustez do código

6.7.5 Exemplo Prático: Sistema de Notas

Vamos acompanhar a evolução de um programa simples que gerencia notas de alunos. Começaremos com código “ruim” e, através de três iterações de refatoração, chegaremos a um código limpo e profissional.

🎯 Objetivo: Ao final desta seção, você será capaz de identificar problemas no código e aplicar técnicas de refatoração para melhorá-lo.

6.7.6 Iteração 1: Código Inicial (Problemas Identificados)

Vamos começar com um programa que funciona, mas tem vários problemas. Este código gerencia notas de três alunos:

# Código inicial - PROBLEMÁTICO
# Problema 1: Código repetido para cada aluno
nome1 = input("Digite o nome do primeiro aluno: ")
nota1_1 = float(input("Digite a primeira nota: "))
nota1_2 = float(input("Digite a segunda nota: "))
nota1_3 = float(input("Digite a terceira nota: "))
media1 = (nota1_1 + nota1_2 + nota1_3) / 3  # Problema 2: Número mágico (3)
print(f"{nome1}: {media1:.2f}")

nome2 = input("Digite o nome do segundo aluno: ")
nota2_1 = float(input("Digite a primeira nota: "))
nota2_2 = float(input("Digite a segunda nota: "))
nota2_3 = float(input("Digite a terceira nota: "))
media2 = (nota2_1 + nota2_2 + nota2_3) / 3  # Problema 2: Repetição do cálculo
print(f"{nome2}: {media2:.2f}")

nome3 = input("Digite o nome do terceiro aluno: ")
nota3_1 = float(input("Digite a primeira nota: "))
nota3_2 = float(input("Digite a segunda nota: "))
nota3_3 = float(input("Digite a terceira nota: "))
media3 = (nota3_1 + nota3_2 + nota3_3) / 3  # Problema 2: Mais repetição
print(f"{nome3}: {media3:.2f}")

# Problema 3: Código para calcular média geral repetido
media_geral = (media1 + media2 + media3) / 3  # Problema 2: Outro número mágico
print(f"Média geral: {media_geral:.2f}")

6.7.7 Problemas Identificados:

  1. 🔄 Código Duplicado: O mesmo bloco de código se repete 3 vezes
  2. 🔢 Números Mágicos: O número 3 aparece várias vezes sem explicação
  3. 📝 Nomes Confusos: Variáveis como nota1_1, nota2_1 são difíceis de entender
  4. 📏 Função Muito Longa: Todo o código está em um bloco único
  5. 🚫 Sem Validação: Não verifica se as notas são válidas (0-10)

6.7.8 Primeira Refatoração: Extrair Funções

Vamos resolver o problema mais crítico primeiro: eliminar a duplicação de código criando funções:

# Primeira refatoração - Extraindo funções
def calcular_media(nota1, nota2, nota3):
    return (nota1 + nota2 + nota3) / 3

def processar_aluno():
    nome = input("Digite o nome do aluno: ")
    nota1 = float(input("Digite a primeira nota: "))
    nota2 = float(input("Digite a segunda nota: "))
    nota3 = float(input("Digite a terceira nota: "))
    media = calcular_media(nota1, nota2, nota3)
    print(f"{nome}: {media:.2f}")
    return media

# Programa principal
media1 = processar_aluno()
media2 = processar_aluno()
media3 = processar_aluno()

media_geral = (media1 + media2 + media3) / 3
print(f"Média geral: {media_geral:.2f}")

6.7.9 Melhorias Feitas:

Eliminamos código duplicado - Criamos a função processar_aluno()
Extraímos cálculo de média - Função calcular_media() reutilizável
Reduzimos o código principal - De 20+ linhas para apenas 6 linhas
Melhoramos a legibilidade - Cada função tem uma responsabilidade clara

💡 Resultado: O código agora é mais curto, mais fácil de entender e mais fácil de modificar. Se quisermos adicionar um quarto aluno, basta chamar processar_aluno() mais uma vez!

6.7.10 Iteração 2: Melhorando Nomes e Constantes

O código já está melhor, mas ainda podemos melhorar. Vamos focar em nomes mais descritivos e eliminar números mágicos:

# Segunda refatoração - Melhorando nomes e constantes
QUANTIDADE_NOTAS = 3  # Constante para eliminar números mágicos
QUANTIDADE_ALUNOS = 3

def calcular_media_aritmetica(primeira_nota, segunda_nota, terceira_nota):
    """Calcula a média aritmética de três notas."""
    soma_das_notas = primeira_nota + segunda_nota + terceira_nota
    return soma_das_notas / QUANTIDADE_NOTAS

def solicitar_dados_do_aluno():
    """Solicita e retorna os dados de um aluno."""
    nome_do_aluno = input("Digite o nome do aluno: ")
    
    primeira_nota = float(input("Digite a primeira nota: "))
    segunda_nota = float(input("Digite a segunda nota: "))
    terceira_nota = float(input("Digite a terceira nota: "))
    
    return nome_do_aluno, primeira_nota, segunda_nota, terceira_nota

def processar_aluno():
    """Processa os dados de um aluno e retorna sua média."""
    nome, nota1, nota2, nota3 = solicitar_dados_do_aluno()
    media_calculada = calcular_media_aritmetica(nota1, nota2, nota3)
    
    print(f"{nome}: {media_calculada:.2f}")
    return media_calculada

def calcular_media_geral(lista_de_medias):
    """Calcula a média geral de uma lista de médias."""
    soma_total = sum(lista_de_medias)
    return soma_total / len(lista_de_medias)

# Programa principal
medias_dos_alunos = []
for i in range(QUANTIDADE_ALUNOS):
    media_individual = processar_aluno()
    medias_dos_alunos.append(media_individual)

media_geral_calculada = calcular_media_geral(medias_dos_alunos)
print(f"Média geral: {media_geral_calculada:.2f}")

6.7.11 Melhorias Feitas:

Nomes Descritivos: calcular_media_aritmetica() em vez de calcular_media()
Constantes: QUANTIDADE_NOTAS e QUANTIDADE_ALUNOS substituem números mágicos
Funções Menores: Quebramos processar_aluno() em funções mais específicas
Documentação: Adicionamos docstrings explicando o que cada função faz
Flexibilidade: calcular_media_geral() funciona com qualquer quantidade de alunos
Loop: Usamos for em vez de repetir código manualmente

6.7.12 Problemas que Ainda Restam:

  1. 🚫 Sem Validação: Ainda não verificamos se as notas são válidas (0-10)
  2. 📊 Sem Estrutura de Dados: Usamos listas simples, mas poderíamos usar dicionários
  3. 🔄 Função Muito Longa: solicitar_dados_do_aluno() ainda faz muitas coisas
  4. 📝 Sem Tratamento de Erros: Se o usuário digitar texto em vez de número, o programa quebra

💡 Resultado: O código agora é mais profissional, com nomes claros e constantes bem definidas. É muito mais fácil entender o que cada parte faz!

6.7.13 Iteração 3: Versão Final (Código Profissional)

Agora vamos criar a versão final, resolvendo todos os problemas restantes e aplicando as melhores práticas:

# Terceira refatoração - Versão final profissional
QUANTIDADE_NOTAS = 3
QUANTIDADE_ALUNOS = 3
NOTA_MINIMA = 0.0
NOTA_MAXIMA = 10.0

def validar_nota(nota):
    """Valida se a nota está dentro do intervalo permitido."""
    return NOTA_MINIMA <= nota <= NOTA_MAXIMA

def solicitar_nota_valida(mensagem):
    """Solicita uma nota válida do usuário."""
    while True:
        try:
            nota = float(input(mensagem))
            if validar_nota(nota):
                return nota
            else:
                print(f"Erro: Nota deve estar entre {NOTA_MINIMA} e {NOTA_MAXIMA}")
        except ValueError:
            print("Erro: Digite um número válido")

def solicitar_nome_aluno():
    """Solicita o nome do aluno."""
    nome = input("Digite o nome do aluno: ").strip()
    if not nome:
        print("Erro: Nome não pode estar vazio")
        return solicitar_nome_aluno()
    return nome

def calcular_media_aritmetica(notas):
    """Calcula a média aritmética de uma lista de notas."""
    return sum(notas) / len(notas)

def processar_aluno():
    """Processa os dados de um aluno e retorna um dicionário com suas informações."""
    nome = solicitar_nome_aluno()
    
    notas = []
    for i in range(QUANTIDADE_NOTAS):
        mensagem = f"Digite a {i+1}ª nota: "
        nota = solicitar_nota_valida(mensagem)
        notas.append(nota)
    
    media = calcular_media_aritmetica(notas)
    
    aluno = {
        "nome": nome,
        "notas": notas,
        "media": media
    }
    
    print(f"{nome}: {media:.2f}")
    return aluno

def calcular_media_geral(alunos):
    """Calcula a média geral de todos os alunos."""
    if not alunos:
        return 0.0
    
    soma_medias = sum(aluno["media"] for aluno in alunos)
    return soma_medias / len(alunos)

def exibir_relatorio_final(alunos, media_geral):
    """Exibe um relatório final com todas as informações."""
    print("\n" + "="*50)
    print("RELATÓRIO FINAL")
    print("="*50)
    
    for aluno in alunos:
        print(f"Aluno: {aluno['nome']}")
        print(f"Notas: {aluno['notas']}")
        print(f"Média: {aluno['media']:.2f}")
        print("-" * 30)
    
    print(f"Média geral da turma: {media_geral:.2f}")
    print("="*50)

def main():
    """Função principal do programa."""
    print("=== SISTEMA DE NOTAS ===")
    
    alunos = []
    for i in range(QUANTIDADE_ALUNOS):
        print(f"\n--- Aluno {i+1} ---")
        aluno = processar_aluno()
        alunos.append(aluno)
    
    media_geral = calcular_media_geral(alunos)
    exibir_relatorio_final(alunos, media_geral)

# Executa o programa
if __name__ == "__main__":
    main()

6.7.14 Melhorias Finais Implementadas:

Validação Completa: Verificamos se notas estão entre 0 e 10
Tratamento de Erros: Capturamos erros de entrada inválida
Estrutura de Dados: Usamos dicionários para organizar dados do aluno
Funções Pequenas: Cada função tem uma única responsabilidade
Documentação: Docstrings em todas as funções
Interface Amigável: Mensagens claras e formatação profissional
Flexibilidade: Fácil de modificar quantidade de alunos ou notas
Robustez: Programa não quebra com entradas inválidas

6.7.15 Comparação: Antes vs. Depois

Aspecto Código Inicial Código Final
Duplicação Muito código repetido Zero duplicação
Legibilidade Difícil de entender Muito clara
Manutenibilidade Difícil de modificar Fácil de estender
Robustez Quebra facilmente Trata erros
Profissionalismo Código amador Código profissional

💡 Resultado Final: Transformamos um código simples e problemático em um sistema robusto, bem documentado e fácil de manter. Este é o poder da refatoração!

6.7.16 Princípios e Dicas de Refatoração

Agora que acompanhamos um exemplo completo de refatoração, vamos consolidar os princípios fundamentais:

6.7.16.1 Técnicas de Refatoração Aprendidas

  1. Extrair Funções (Extract Functions)
    • Transforme código repetido em funções reutilizáveis
    • Cada função deve ter uma responsabilidade clara
    • Nomes descritivos explicam o que a função faz
  2. Melhorar Nomes (Improve Naming)
    • Use nomes que expliquem o propósito da variável/função
    • Evite abreviações confusas (temp, x, dados)
    • Prefira calcular_media_aritmetica() a calc_med()
  3. Eliminar Código Duplicado (Remove Duplication)
    • Se você está copiando e colando código, crie uma função
    • DRY: “Don’t Repeat Yourself” (Não se repita)
    • Uma mudança deve ser feita em apenas um lugar
  4. Reduzir Complexidade (Reduce Complexity)
    • Quebre funções grandes em funções menores
    • Uma função deve fazer apenas uma coisa bem feita
    • Use constantes em vez de números mágicos
  5. Adicionar Validações (Add Validation)
    • Verifique se os dados de entrada são válidos
    • Trate erros graciosamente
    • Forneça mensagens de erro claras

6.7.16.2 Quando NÃO Refatorar

  • Se o código funciona perfeitamente e não será modificado
  • Se você não tem tempo para testar as mudanças adequadamente
  • Se a refatoração é muito arriscada para o prazo do projeto
  • Se você não entende completamente o código existente

💡 Dica Importante: Refatoração deve ser feita gradualmente e sempre com testes para garantir que o comportamento não mudou.

6.7.16.3 Dicas Práticas para Iniciantes

  1. Comece Pequeno: Refatore uma função por vez, não todo o programa
  2. Teste Sempre: Execute o código após cada mudança para garantir que funciona
  3. Use Git: Salve versões do código antes de refatorar (controle de versão)
  4. Documente: Adicione comentários explicando o que cada função faz
  5. Pratique: Quanto mais você refatora, mais natural se torna

6.7.16.4 Sinais de que Precisa Refatorar

  • Código duplicado em vários lugares
  • Funções muito longas (mais de 20-30 linhas)
  • Nomes confusos que não explicam o propósito
  • Números mágicos espalhados pelo código
  • Código difícil de entender mesmo para quem escreveu
  • Muitos comentários explicando código confuso

6.7.16.5 Benefícios da Refatoração

  • Manutenibilidade: Mais fácil de corrigir bugs e adicionar funcionalidades
  • Legibilidade: Código mais fácil de entender
  • Reutilização: Funções podem ser usadas em outros projetos
  • Confiabilidade: Menos bugs devido à melhor organização
  • Produtividade: Desenvolvimento mais rápido no futuro

🎓 Lembre-se: Refatoração é uma habilidade que se desenvolve com a prática. Quanto mais você aplicar essas técnicas, mais natural se tornará identificar oportunidades de melhoria no código.


🎉 Parabéns! Você agora domina os conceitos fundamentais de refatoração e pode aplicar essas técnicas para escrever código mais limpo e profissional!

6.8 Exercícios Práticos (respostas no final da página)

🚀 Hora de praticar! Aqui estão 25 exercícios organizados por dificuldade. Cada exercício tem solução completa com explicação linha por linha!

6.8.1 MUITO FÁCIL (Nível 1)

1. Função de Saudação Crie uma função chamada dizer_ola que não recebe parâmetros e apenas mostra “Olá, mundo!” na tela.

  • Exemplo: Output → Olá, mundo!

2. Função de Soma Crie uma função chamada somar que recebe dois números e retorna a soma deles.

  • Exemplo: Input → 5, 3 | Output → 8

3. Função de Multiplicação Crie uma função chamada multiplicar que recebe dois números e retorna a multiplicação deles.

  • Exemplo: Input → 4, 7 | Output → 28

4. Função de Quadrado Crie uma função chamada quadrado que recebe um número e retorna seu quadrado.

  • Exemplo: Input → 6 | Output → 36

5. Função de Nome Crie uma função chamada mostrar_nome que recebe um nome e mostra “Olá, [nome]!” na tela.

  • Exemplo: Input → "Maria" | Output → Olá, Maria!

6.8.2 FÁCIL (Nível 2)

6. Média de Notas Crie uma função que recebe três notas e retorna a média dessas notas.

  • Exemplo: Input → 8.5, 9.0, 7.1 | Output → A média é: 8.20

7. Conversão de Temperatura Crie uma função que recebe uma temperatura em Celsius e retorna a temperatura em Fahrenheit.

  • Exemplo: Input → 0 | Output → 0°C = 32.0°F

8. Verificar Par ou Ímpar Crie uma função que recebe um número e retorna “par” se for par ou “ímpar” se for ímpar.

  • Exemplo: Input → 7 | Output → O número 7 é ímpar

9. Área do Retângulo Crie uma função que recebe base e altura de um retângulo e retorna sua área.

  • Exemplo: Input → 5, 8 | Output → A área do retângulo é: 40

10. Maior Número Crie uma função que recebe dois números e retorna o maior deles.

  • Exemplo: Input → 15, 23 | Output → O maior número é: 23

6.8.3 MÉDIO (Nível 3)

11. Fatorial Crie uma função que recebe um número e retorna seu fatorial.

  • Exemplo: Input → 5 | Output → O fatorial de 5 é: 120

12. Verificar Número Primo Crie uma função que recebe um número e retorna True se for primo ou False se não for primo.

  • Exemplo: Input → 17 | Output → 17 é primo? True

13. Contar Vogais Crie uma função que recebe uma palavra e retorna o número de vogais nela.

  • Exemplo: Input → "Python" | Output → A palavra 'Python' tem 1 vogal

14. Inverter String Crie uma função que recebe uma string e retorna ela invertida.

  • Exemplo: Input → "Python" | Output → A palavra 'Python' invertida é: nohtyP

15. Verificar Palíndromo Crie uma função que recebe uma palavra e retorna True se for palíndromo ou False se não for.

  • Exemplo: Input → "arara" | Output → 'arara' é palíndromo? True

6.8.4 DIFÍCIL (Nível 4)

16. Calculadora com Funções Crie uma calculadora usando funções. Crie funções para somar, subtrair, multiplicar e dividir. Depois crie uma função principal que usa essas funções.

  • Exemplo: Input → 1, 10, 5 | Output → 10 + 5 = 15

17. Gerador de Senha Crie uma função que gera uma senha aleatória com 8 caracteres (letras e números).

  • Exemplo: Output → Sua nova senha é: A7bK9mP2

18. Verificar CPF Crie uma função que verifica se um CPF tem 11 dígitos e contém apenas números.

  • Exemplo: Input → "123.456.789-00" | Output → CPF válido!

19. Contador de Palavras Crie uma função que recebe um texto e retorna o número de palavras nele.

  • Exemplo: Input → "Python é uma linguagem de programação muito poderosa" | Output → O texto tem 8 palavras

20. Fibonacci Crie uma função que recebe um número n e retorna os primeiros n números da sequência de Fibonacci.

  • Exemplo: Input → 10 | Output → Primeiros 10 números de Fibonacci: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

6.8.5 MUITO DIFÍCIL (Nível 5)

21. Sistema de Cadastro Crie um sistema de cadastro usando funções. Crie funções para cadastrar, listar e buscar usuários.

  • Exemplo: Input → 1, João, joao@email.com, 252 | Output → Usuário cadastrado!, 1. Nome: João, Email: joao@email.com, Idade: 25

22. Jogo da Forca com Funções Crie um jogo da forca usando funções. Separe as responsabilidades em diferentes funções.

  • Exemplo: Input → python | Output → Letra encontrada!, ..., Parabéns! Você ganhou! A palavra era: python

23. Calculadora de IMC com Histórico Crie uma calculadora de IMC que armazene o histórico usando funções.

  • Exemplo: Input → 1, João, 70, 1.752 | Output → João: IMC 22.86 - Peso normal, 1. João: IMC 22.86 - Peso normal

24. Sistema de Notas com Funções Crie um sistema de notas usando funções para cadastrar alunos, adicionar notas e calcular médias.

  • Exemplo: Input → 1, Ana2, Ana, 8.53, Ana | Output → Aluno Ana cadastrado!, Nota 8.5 adicionada, Média de Ana: 8.50

25. Sistema Bancário com Funções Crie um sistema bancário usando funções para depósito, saque e consulta de saldo.

  • Exemplo: Input → 1, 10032, 504 | Output → Depósito de R$ 100.00 realizado!, Saldo atual: R$ 100.00, Saque de R$ 50.00 realizado!, Obrigado por usar o Banco Python!

6.9 Respostas e Explicações

6.9.1 MUITO FÁCIL (Nível 1)

1. Função de Saudação

def dizer_ola():
    print("Olá, mundo!")

dizer_ola()

Explicação linha por linha:

  • Linha 1: def dizer_ola(): - Define a função com nome descritivo e sem parâmetros
  • Linha 2: print("Olá, mundo!") - Mostra mensagem na tela
  • Linha 4: dizer_ola() - Chama a função para executar o código dentro dela

2. Função de Soma

def somar(a, b):
    return a + b

resultado = somar(5, 3)
print(resultado)

Explicação linha por linha:

  • Linha 1: def somar(a, b): - Define função com dois parâmetros (a e b)
  • Linha 2: return a + b - Retorna a soma dos dois parâmetros
  • Linha 4: resultado = somar(5, 3) - Chama função com valores específicos e guarda resultado
  • Linha 5: print(resultado) - Mostra o resultado na tela

3. Função de Multiplicação

def multiplicar(x, y):
    return x * y

produto = multiplicar(4, 7)
print(produto)

Explicação linha por linha:

  • Linha 1: def multiplicar(x, y): - Define função com parâmetros x e y
  • Linha 2: return x * y - Retorna a multiplicação dos parâmetros
  • Linha 4: produto = multiplicar(4, 7) - Chama função com valores específicos
  • Linha 5: print(produto) - Mostra o resultado da multiplicação

4. Função de Quadrado

def quadrado(numero):
    return numero ** 2

resultado = quadrado(6)
print(resultado)

Explicação linha por linha:

  • Linha 1: def quadrado(numero): - Define função que recebe um número como parâmetro
  • Linha 2: return numero ** 2 - Retorna o número elevado ao quadrado (potência 2)
  • Linha 4: resultado = quadrado(6) - Chama função com valor 6
  • Linha 5: print(resultado) - Mostra o resultado (36)

5. Função de Nome

def mostrar_nome(nome):
    print(f"Olá, {nome}!")

mostrar_nome("Maria")

Explicação linha por linha:

  • Linha 1: def mostrar_nome(nome): - Define função com parâmetro nome
  • Linha 2: print(f"Olá, {nome}!") - Usa f-string para mostrar saudação personalizada
  • Linha 4: mostrar_nome("Maria") - Chama função com nome específico

6.9.2 FÁCIL (Nível 2)

6. Média de Notas

def calcular_media(nota1, nota2, nota3):
    media = (nota1 + nota2 + nota3) / 3
    return media

resultado = calcular_media(8.5, 9.0, 7.1)
print(f"A média é: {resultado:.2f}")

Explicação linha por linha:

  • Linha 1: def calcular_media(nota1, nota2, nota3): - Define função com três parâmetros para as notas
  • Linha 2: media = (nota1 + nota2 + nota3) / 3 - Calcula a média aritmética das três notas
  • Linha 3: return media - Retorna o valor da média calculada
  • Linha 5: resultado = calcular_media(8.5, 9.0, 7.1) - Chama função com notas específicas
  • Linha 6: print(f"A média é: {resultado:.2f}") - Mostra resultado formatado com 2 casas decimais

7. Conversão de Temperatura

def celsius_para_fahrenheit(temp_celsius):
    temp_fahrenheit = (temp_celsius * 9/5) + 32
    return temp_fahrenheit

temperatura = celsius_para_fahrenheit(0)
print(f"0°C = {temperatura}°F")

Explicação linha por linha:

  • Linha 1: def celsius_para_fahrenheit(temp_celsius): - Define função de conversão de temperatura
  • Linha 2: temp_fahrenheit = (temp_celsius * 9/5) + 32 - Aplica fórmula de conversão de Celsius para Fahrenheit
  • Linha 3: return temp_fahrenheit - Retorna temperatura convertida em Fahrenheit
  • Linha 5: temperatura = celsius_para_fahrenheit(0) - Chama função com 0°C como exemplo
  • Linha 6: print(f"0°C = {temperatura}°F") - Mostra resultado da conversão

8. Verificar Par ou Ímpar

def verificar_par_impar(numero):
    if numero % 2 == 0:
        return "par"
    else:
        return "ímpar"

resultado = verificar_par_impar(7)
print(f"O número 7 é {resultado}")

Explicação linha por linha:

  • Linha 1: def verificar_par_impar(numero): - Define função para verificar se número é par ou ímpar
  • Linha 2: if numero % 2 == 0: - Verifica se resto da divisão por 2 é zero (número par)
  • Linha 3: return "par" - Retorna string “par” se condição for verdadeira
  • Linha 5: return "ímpar" - Retorna string “ímpar” se condição for falsa
  • Linha 7: resultado = verificar_par_impar(7) - Chama função com número 7
  • Linha 8: print(f"O número 7 é {resultado}") - Mostra resultado da verificação

9. Área do Retângulo

def calcular_area_retangulo(base, altura):
    area = base * altura
    return area

area = calcular_area_retangulo(5, 8)
print(f"A área do retângulo é: {area}")

Explicação linha por linha:

  • Linha 1: def calcular_area_retangulo(base, altura): - Define função com dois parâmetros (base e altura)
  • Linha 2: area = base * altura - Calcula área multiplicando base por altura
  • Linha 3: return area - Retorna valor da área calculada
  • Linha 5: area = calcular_area_retangulo(5, 8) - Chama função com valores específicos
  • Linha 6: print(f"A área do retângulo é: {area}") - Mostra resultado do cálculo

10. Maior Número

def maior_numero(a, b):
    if a > b:
        return a
    else:
        return b

resultado = maior_numero(15, 23)
print(f"O maior número é: {resultado}")

Explicação linha por linha:

  • Linha 1: def maior_numero(a, b): - Define função para comparar dois números
  • Linha 2: if a > b: - Verifica se o primeiro número é maior que o segundo
  • Linha 3: return a - Retorna a se for maior
  • Linha 5: return b - Retorna b se for maior ou igual
  • Linha 7: resultado = maior_numero(15, 23) - Chama função com valores específicos
  • Linha 8: print(f"O maior número é: {resultado}") - Mostra o maior número encontrado

6.9.3 MÉDIO (Nível 3)

11. Fatorial

def calcular_fatorial(numero):
    fatorial = 1
    for i in range(1, numero + 1):
        fatorial *= i
    return fatorial

resultado = calcular_fatorial(5)
print(f"O fatorial de 5 é: {resultado}")

Explicação linha por linha:

  • Linha 1: def calcular_fatorial(numero): - Define função para calcular fatorial de um número
  • Linha 2: fatorial = 1 - Inicializa variável fatorial com 1 (elemento neutro da multiplicação)
  • Linha 3: for i in range(1, numero + 1): - Loop que vai de 1 até o número fornecido
  • Linha 4: fatorial *= i - Multiplica fatorial por cada número do loop (equivalente a fatorial = fatorial * i)
  • Linha 5: return fatorial - Retorna o fatorial calculado
  • Linha 7: resultado = calcular_fatorial(5) - Chama função com valor 5
  • Linha 8: print(f"O fatorial de 5 é: {resultado}") - Mostra resultado do cálculo

12. Verificar Número Primo

def verificar_primo(numero):
    if numero < 2:
        return False
    for i in range(2, numero):
        if numero % i == 0:
            return False
    return True

resultado = verificar_primo(17)
print(f"17 é primo? {resultado}")

Explicação linha por linha:

  • Linha 1: def verificar_primo(numero): - Define função para verificar se número é primo
  • Linha 2: if numero < 2: - Verifica se número é menor que 2
  • Linha 3: return False - Retorna False (números menores que 2 não são primos)
  • Linha 4: for i in range(2, numero): - Loop que vai de 2 até número-1
  • Linha 5: if numero % i == 0: - Verifica se número é divisível por i (resto da divisão é zero)
  • Linha 6: return False - Retorna False se encontrar algum divisor
  • Linha 7: return True - Retorna True se não encontrar divisores (número é primo)
  • Linha 9: resultado = verificar_primo(17) - Chama função com valor 17
  • Linha 10: print(f"17 é primo? {resultado}") - Mostra resultado da verificação

13. Contar Vogais

def contar_vogais(palavra):
    vogais = "aeiouAEIOU"
    contador = 0
    for letra in palavra:
        if letra in vogais:
            contador += 1
    return contador

resultado = contar_vogais("Python")
print(f"A palavra 'Python' tem {resultado} vogais")

Explicação linha por linha:

  • Linha 1: def contar_vogais(palavra): - Define função para contar vogais em uma palavra
  • Linha 2: vogais = "aeiouAEIOU" - Define string com todas as vogais (maiúsculas e minúsculas)
  • Linha 3: contador = 0 - Inicializa contador de vogais
  • Linha 4: for letra in palavra: - Loop que percorre cada letra da palavra
  • Linha 5: if letra in vogais: - Verifica se a letra atual é uma vogal
  • Linha 6: contador += 1 - Incrementa contador se letra for vogal
  • Linha 7: return contador - Retorna número total de vogais encontradas
  • Linha 9: resultado = contar_vogais("Python") - Chama função com palavra específica
  • Linha 10: print(f"A palavra 'Python' tem {resultado} vogais") - Mostra resultado da contagem

14. Inverter String

def inverter_string(texto):
    texto_invertido = ""
    for i in range(len(texto) - 1, -1, -1):
        texto_invertido += texto[i]
    return texto_invertido

resultado = inverter_string("Python")
print(f"A palavra 'Python' invertida é: {resultado}")

Explicação linha por linha:

  • Linha 1: def inverter_string(texto): - Define função para inverter uma string
  • Linha 2: texto_invertido = "" - Inicializa string vazia para armazenar resultado
  • Linha 3: for i in range(len(texto) - 1, -1, -1): - Loop que vai do último caractere ao primeiro (ordem decrescente)
  • Linha 4: texto_invertido += texto[i] - Adiciona cada caractere na ordem inversa à string resultado
  • Linha 5: return texto_invertido - Retorna string invertida
  • Linha 7: resultado = inverter_string("Python") - Chama função com palavra específica
  • Linha 8: print(f"A palavra 'Python' invertida é: {resultado}") - Mostra resultado da inversão

15. Verificar Palíndromo

def verificar_palindromo(palavra):
    palavra = palavra.lower()  # Converte para minúscula
    i = 0
    j = len(palavra) - 1
    while i < j:
        if palavra[i] != palavra[j]:
            return False
        i += 1
        j -= 1
    return True

resultado = verificar_palindromo("arara")
print(f"'arara' é palíndromo? {resultado}")

Explicação linha por linha:

  • Linha 1: def verificar_palindromo(palavra): - Define função para verificar se palavra é palíndromo
  • Linha 2: palavra = palavra.lower() - Converte palavra para minúscula para comparação
  • Linha 3: i = 0 - Inicializa contador do início da palavra
  • Linha 4: j = len(palavra) - 1 - Inicializa contador do final da palavra
  • Linha 5: while i < j: - Loop continua enquanto contadores não se cruzam
  • Linha 6: if palavra[i] != palavra[j]: - Verifica se caracteres nas posições i e j são diferentes
  • Linha 7: return False - Retorna False se não for palíndromo
  • Linha 8: i += 1 - Move contador do início para frente
  • Linha 9: j -= 1 - Move contador do final para trás
  • Linha 10: return True - Retorna True se for palíndromo
  • Linha 12: resultado = verificar_palindromo("arara") - Chama função com palavra específica
  • Linha 13: print(f"'arara' é palíndromo? {resultado}") - Mostra resultado da verificação

6.9.4 DIFÍCIL (Nível 4)

16. Calculadora com Funções

def somar(a, b):
    return a + b

def subtrair(a, b):
    return a - b

def multiplicar(a, b):
    return a * b

def dividir(a, b):
    if b != 0:
        return a / b
    else:
        return "Erro: Divisão por zero!"

def calculadora():
    print("=== CALCULADORA ===")
    print("1. Somar")
    print("2. Subtrair")
    print("3. Multiplicar")
    print("4. Dividir")
    
    opcao = input("Escolha uma operação (1-4): ")
    num1 = float(input("Digite o primeiro número: "))
    num2 = float(input("Digite o segundo número: "))
    
    if opcao == "1":
        resultado = somar(num1, num2)
        print(f"{num1} + {num2} = {resultado}")
    elif opcao == "2":
        resultado = subtrair(num1, num2)
        print(f"{num1} - {num2} = {resultado}")
    elif opcao == "3":
        resultado = multiplicar(num1, num2)
        print(f"{num1} x {num2} = {resultado}")
    elif opcao == "4":
        resultado = dividir(num1, num2)
        print(f"{num1} ÷ {num2} = {resultado}")
    else:
        print("Opção inválida!")

calculadora()

Explicação linha por linha:

  • Linhas 1-15: Definem funções para cada operação matemática (somar, subtrair, multiplicar, dividir)
  • Linha 17: def calculadora(): - Define função principal da calculadora
  • Linhas 18-22: Mostram menu de opções disponíveis
  • Linha 24: opcao = input("Escolha uma operação (1-4): ") - Solicita escolha do usuário
  • Linhas 25-26: Pedem os dois números para realizar o cálculo
  • Linhas 28-39: Verificam opção escolhida e executam operação correspondente
  • Linha 41: calculadora() - Chama função principal para iniciar a calculadora

17. Gerador de Senha

import random
import string

def gerar_senha():
    caracteres = string.ascii_letters + string.digits
    senha = ""
    for i in range(8):
        senha += random.choice(caracteres)
    return senha

senha_gerada = gerar_senha()
print(f"Sua nova senha é: {senha_gerada}")

Explicação linha por linha:

  • Linha 1: import random - Importa módulo para gerar números aleatórios
  • Linha 2: import string - Importa módulo para trabalhar com strings e caracteres
  • Linha 4: def gerar_senha(): - Define função para gerar senha aleatória
  • Linha 5: caracteres = string.ascii_letters + string.digits - Combina letras maiúsculas, minúsculas e números
  • Linha 6: senha = "" - Inicializa string vazia para armazenar senha
  • Linha 7: for i in range(8): - Loop para gerar exatamente 8 caracteres
  • Linha 8: senha += random.choice(caracteres) - Adiciona caractere aleatório escolhido da string de caracteres
  • Linha 9: return senha - Retorna senha gerada
  • Linha 11: senha_gerada = gerar_senha() - Chama função e armazena resultado
  • Linha 12: print(f"Sua nova senha é: {senha_gerada}") - Mostra senha gerada

18. Verificar CPF

def verificar_cpf(cpf):
    # Remove pontos e traços se existirem
    cpf = cpf.replace(".", "").replace("-", "")
    
    # Verifica se tem 11 dígitos
    if len(cpf) != 11:
        return False
    
    # Verifica se contém apenas números
    if not cpf.isdigit():
        return False
    
    return True

cpf_teste = "123.456.789-00"
if verificar_cpf(cpf_teste):
    print("CPF válido!")
else:
    print("CPF inválido!")

Explicação linha por linha:

  • Linha 1: def verificar_cpf(cpf): - Define função para verificar validade de CPF
  • Linha 3: cpf = cpf.replace(".", "").replace("-", "") - Remove pontos e traços da string CPF
  • Linha 6: if len(cpf) != 11: - Verifica se CPF tem exatamente 11 dígitos
  • Linha 7: return False - Retorna False se não tiver 11 dígitos
  • Linha 10: if not cpf.isdigit(): - Verifica se CPF contém apenas números
  • Linha 11: return False - Retorna False se contiver caracteres não numéricos
  • Linha 13: return True - Retorna True se CPF for válido (11 dígitos numéricos)
  • Linha 15: cpf_teste = "123.456.789-00" - Define CPF de exemplo para testar
  • Linhas 16-19: Verificam se CPF é válido e mostram resultado correspondente

19. Contador de Palavras

def contar_palavras(texto):
    palavras = texto.split()
    return len(palavras)

texto = "Python é uma linguagem de programação muito poderosa"
numero_palavras = contar_palavras(texto)
print(f"O texto tem {numero_palavras} palavras")

Explicação linha por linha:

  • Linha 1: def contar_palavras(texto): - Define função para contar palavras em um texto
  • Linha 2: palavras = texto.split() - Divide texto em lista de palavras usando espaços como separador
  • Linha 3: return len(palavras) - Retorna número de palavras (tamanho da lista)
  • Linha 5: texto = "Python é uma linguagem de programação muito poderosa" - Define texto de exemplo
  • Linha 6: numero_palavras = contar_palavras(texto) - Chama função e armazena resultado
  • Linha 7: print(f"O texto tem {numero_palavras} palavras") - Mostra número de palavras encontradas

20. Fibonacci

def fibonacci(n):
    if n <= 0:
        return []
    elif n == 1:
        return [0]
    elif n == 2:
        return [0, 1]
    else:
        sequencia = [0, 1]
        for i in range(2, n):
            proximo = sequencia[i-1] + sequencia[i-2]
            sequencia.append(proximo)
        return sequencia

resultado = fibonacci(10)
print(f"Primeiros 10 números de Fibonacci: {resultado}")

Explicação linha por linha:

  • Linha 1: def fibonacci(n): - Define função para gerar sequência de Fibonacci
  • Linha 2: if n <= 0: - Verifica se n é menor ou igual a zero
  • Linha 3: return [] - Retorna lista vazia se n for inválido
  • Linha 4: elif n == 1: - Verifica se n é igual a 1
  • Linha 5: return [0] - Retorna lista contendo apenas o primeiro número da sequência
  • Linha 6: elif n == 2: - Verifica se n é igual a 2
  • Linha 7: return [0, 1] - Retorna lista com os dois primeiros números
  • Linha 9: sequencia = [0, 1] - Inicializa sequência com os dois primeiros números
  • Linha 10: for i in range(2, n): - Loop para gerar números restantes da sequência
  • Linha 11: proximo = sequencia[i-1] + sequencia[i-2] - Calcula próximo número somando os dois anteriores
  • Linha 12: sequencia.append(proximo) - Adiciona próximo número à sequência
  • Linha 13: return sequencia - Retorna sequência completa
  • Linha 15: resultado = fibonacci(10) - Chama função para gerar 10 números
  • Linha 16: print(f"Primeiros 10 números de Fibonacci: {resultado}") - Mostra sequência gerada

6.9.5 MUITO DIFÍCIL (Nível 5)

21. Sistema de Cadastro

usuarios = []

def cadastrar_usuario():
    nome = input("Digite o nome: ")
    email = input("Digite o email: ")
    idade = int(input("Digite a idade: "))
    
    usuario = {
        "nome": nome,
        "email": email,
        "idade": idade
    }
    
    usuarios.append(usuario)
    print("Usuário cadastrado com sucesso!")

def listar_usuarios():
    if not usuarios:
        print("Nenhum usuário cadastrado!")
    else:
        print("=== LISTA DE USUÁRIOS ===")
        for i, usuario in enumerate(usuarios, 1):
            print(f"{i}. Nome: {usuario['nome']}, Email: {usuario['email']}, Idade: {usuario['idade']}")

def buscar_usuario():
    nome_busca = input("Digite o nome para buscar: ")
    encontrados = []
    
    for usuario in usuarios:
        if nome_busca.lower() in usuario["nome"].lower():
            encontrados.append(usuario)
    
    if encontrados:
        print("=== USUÁRIOS ENCONTRADOS ===")
        for usuario in encontrados:
            print(f"Nome: {usuario['nome']}, Email: {usuario['email']}, Idade: {usuario['idade']}")
    else:
        print("Nenhum usuário encontrado!")

def menu():
    while True:
        print("\n=== SISTEMA DE CADASTRO ===")
        print("1. Cadastrar usuário")
        print("2. Listar usuários")
        print("3. Buscar usuário")
        print("4. Sair")
        
        opcao = input("Escolha uma opção: ")
        
        if opcao == "1":
            cadastrar_usuario()
        elif opcao == "2":
            listar_usuarios()
        elif opcao == "3":
            buscar_usuario()
        elif opcao == "4":
            print("Sistema encerrado!")
            break
        else:
            print("Opção inválida!")

menu()

Explicação linha por linha:

  • Linha 1: usuarios = [] - Lista global para armazenar dados dos usuários
  • Linha 3: def cadastrar_usuario(): - Função para cadastrar novo usuário
  • Linhas 4-6: Solicita dados do usuário (nome, email, idade)
  • Linhas 8-12: Cria dicionário com dados do usuário organizados
  • Linha 14: usuarios.append(usuario) - Adiciona usuário à lista global
  • Linha 15: print("Usuário cadastrado com sucesso!") - Confirma cadastro
  • Linha 17: def listar_usuarios(): - Função para listar todos os usuários
  • Linhas 18-24: Verifica se há usuários cadastrados e os lista numerados
  • Linha 26: def buscar_usuario(): - Função para buscar usuários por nome
  • Linhas 27-39: Busca usuários que contenham o nome digitado (case-insensitive)
  • Linha 41: def menu(): - Função principal que controla o sistema
  • Linhas 42-58: Loop infinito que gerencia o menu e chama funções apropriadas

22. Jogo da Forca com Funções

import random

def escolher_palavra():
    palavras = ["python", "programacao", "computador", "algoritmo", "funcao"]
    return random.choice(palavras)

def inicializar_jogo(palavra):
    palavra_oculta = "_" * len(palavra)
    tentativas = 6
    letras_usadas = []
    return palavra_oculta, tentativas, letras_usadas

def mostrar_estado(palavra_oculta, tentativas, letras_usadas):
    print(f"\nPalavra: {palavra_oculta}")
    print(f"Tentativas restantes: {tentativas}")
    print(f"Letras usadas: {letras_usadas}")

def processar_tentativa(palavra, palavra_oculta, letra, letras_usadas):
    if letra in letras_usadas:
        print("Você já usou essa letra!")
        return palavra_oculta, False
    
    letras_usadas.append(letra)
    
    if letra in palavra:
        print("Letra encontrada!")
        nova_palavra_oculta = ""
        for i in range(len(palavra)):
            if palavra[i] == letra:
                nova_palavra_oculta += letra
            else:
                nova_palavra_oculta += palavra_oculta[i]
        return nova_palavra_oculta, True
    else:
        print("Letra não encontrada!")
        return palavra_oculta, False

def verificar_fim_jogo(palavra_oculta, tentativas, palavra):
    if "_" not in palavra_oculta:
        print(f"\nParabéns! Você ganhou! A palavra era: {palavra}")
        return True
    elif tentativas <= 0:
        print(f"\nGame Over! A palavra era: {palavra}")
        return True
    return False

def jogar_forca():
    palavra = escolher_palavra()
    palavra_oculta, tentativas, letras_usadas = inicializar_jogo(palavra)
    
    while not verificar_fim_jogo(palavra_oculta, tentativas, palavra):
        mostrar_estado(palavra_oculta, tentativas, letras_usadas)
        
        letra = input("Digite uma letra: ").lower()
        
        palavra_oculta, acertou = processar_tentativa(palavra, palavra_oculta, letra, letras_usadas)
        
        if not acertou:
            tentativas -= 1

jogar_forca()

Explicação linha por linha:

  • Linha 1: import random - Importa módulo para escolha aleatória de palavras
  • Linha 3: def escolher_palavra(): - Função para escolher palavra aleatória da lista
  • Linha 6: def inicializar_jogo(palavra): - Função para inicializar variáveis do jogo
  • Linha 10: def mostrar_estado(): - Função para mostrar estado atual do jogo
  • Linha 15: def processar_tentativa(): - Função para processar tentativa do jogador
  • Linha 30: def verificar_fim_jogo(): - Função para verificar se jogo acabou
  • Linha 37: def jogar_forca(): - Função principal que coordena todo o jogo
  • Linha 38: palavra = escolher_palavra() - Escolhe palavra aleatória para o jogo
  • Linha 39: palavra_oculta, tentativas, letras_usadas = inicializar_jogo(palavra) - Inicializa variáveis do jogo
  • Linhas 41-47: Loop principal que gerencia o jogo até o fim

23. Calculadora de IMC com Histórico

historico = []

def calcular_imc(peso, altura):
    imc = peso / (altura ** 2)
    return imc

def classificar_imc(imc):
    if imc < 18.5:
        return "Abaixo do peso"
    elif imc < 25:
        return "Peso normal"
    elif imc < 30:
        return "Sobrepeso"
    else:
        return "Obesidade"

def cadastrar_imc():
    nome = input("Digite seu nome: ")
    peso = float(input("Digite seu peso (kg): "))
    altura = float(input("Digite sua altura (m): "))
    
    imc = calcular_imc(peso, altura)
    classificacao = classificar_imc(imc)
    
    resultado = {
        "nome": nome,
        "peso": peso,
        "altura": altura,
        "imc": imc,
        "classificacao": classificacao
    }
    
    historico.append(resultado)
    
    print(f"\n{nome}: IMC {imc:.2f} - {classificacao}")

def ver_historico():
    if not historico:
        print("Nenhum cálculo realizado ainda.")
    else:
        print("\n=== HISTÓRICO ===")
        for i, resultado in enumerate(historico, 1):
            print(f"{i}. {resultado['nome']}: IMC {resultado['imc']:.2f} - {resultado['classificacao']}")

def menu_imc():
    while True:
        print("\n=== CALCULADORA DE IMC ===")
        print("1. Calcular IMC")
        print("2. Ver Histórico")
        print("3. Sair")
        
        opcao = input("Escolha uma opção: ")
        
        if opcao == "1":
            cadastrar_imc()
        elif opcao == "2":
            ver_historico()
        elif opcao == "3":
            print("Obrigado por usar a Calculadora de IMC!")
            break
        else:
            print("Opção inválida!")

menu_imc()

Explicação linha por linha:

  • Linha 1: historico = [] - Lista global para armazenar histórico de cálculos
  • Linha 3: def calcular_imc(peso, altura): - Função para calcular IMC usando fórmula padrão
  • Linha 6: def classificar_imc(imc): - Função para classificar IMC em categorias
  • Linha 15: def cadastrar_imc(): - Função para cadastrar novo cálculo de IMC
  • Linhas 16-18: Solicita dados do usuário (nome, peso, altura)
  • Linhas 20-21: Calcula IMC e classificação
  • Linhas 23-30: Cria dicionário com resultado completo
  • Linha 32: historico.append(resultado) - Adiciona resultado ao histórico
  • Linha 36: def ver_historico(): - Função para mostrar histórico de cálculos
  • Linha 44: def menu_imc(): - Função principal que gerencia o sistema
  • Linhas 45-58: Loop principal que gerencia menu e chama funções apropriadas

24. Sistema de Notas com Funções

alunos = {}

def cadastrar_aluno():
    nome = input("Digite o nome do aluno: ")
    if nome not in alunos:
        alunos[nome] = []
        print(f"Aluno {nome} cadastrado com sucesso!")
    else:
        print("Aluno já cadastrado!")

def adicionar_nota():
    nome = input("Digite o nome do aluno: ")
    if nome in alunos:
        nota = float(input("Digite a nota: "))
        if 0 <= nota <= 10:
            alunos[nome].append(nota)
            print(f"Nota {nota} adicionada para {nome}")
        else:
            print("Nota deve estar entre 0 e 10!")
    else:
        print("Aluno não encontrado!")

def calcular_media():
    nome = input("Digite o nome do aluno: ")
    if nome in alunos and alunos[nome]:
        media = sum(alunos[nome]) / len(alunos[nome])
        print(f"Média de {nome}: {media:.2f}")
    else:
        print("Aluno não encontrado ou sem notas!")

def ver_relatorio():
    print("\n=== RELATÓRIO ===")
    if alunos:
        for nome, notas in alunos.items():
            if notas:
                media = sum(notas) / len(notas)
                print(f"{nome}: {len(notas)} notas, média {media:.2f}")
            else:
                print(f"{nome}: sem notas")
    else:
        print("Nenhum aluno cadastrado!")

def menu_notas():
    while True:
        print("\n=== SISTEMA DE NOTAS ===")
        print("1. Cadastrar Aluno")
        print("2. Adicionar Nota")
        print("3. Calcular Média")
        print("4. Ver Relatório")
        print("5. Sair")
        
        opcao = input("Escolha uma opção: ")
        
        if opcao == "1":
            cadastrar_aluno()
        elif opcao == "2":
            adicionar_nota()
        elif opcao == "3":
            calcular_media()
        elif opcao == "4":
            ver_relatorio()
        elif opcao == "5":
            print("Sistema encerrado!")
            break
        else:
            print("Opção inválida!")

menu_notas()

Explicação linha por linha:

  • Linha 1: alunos = {} - Dicionário global para armazenar alunos e suas notas
  • Linha 3: def cadastrar_aluno(): - Função para cadastrar novo aluno
  • Linha 11: def adicionar_nota(): - Função para adicionar nota a um aluno
  • Linha 23: def calcular_media(): - Função para calcular média de um aluno
  • Linha 31: def ver_relatorio(): - Função para mostrar relatório de todos os alunos
  • Linha 42: def menu_notas(): - Função principal que gerencia o sistema
  • Linhas 43-58: Loop principal que gerencia menu e chama funções apropriadas

25. Sistema Bancário com Funções

saldo = 0

def depositar():
    global saldo
    valor = float(input("Digite o valor do depósito: "))
    if valor > 0:
        saldo += valor
        print(f"Depósito de R$ {valor:.2f} realizado! Saldo atual: R$ {saldo:.2f}")
    else:
        print("Valor inválido!")

def sacar():
    global saldo
    valor = float(input("Digite o valor do saque: "))
    if valor > 0 and valor <= saldo:
        saldo -= valor
        print(f"Saque de R$ {valor:.2f} realizado! Saldo atual: R$ {saldo:.2f}")
    elif valor > saldo:
        print("Saldo insuficiente!")
    else:
        print("Valor inválido!")

def consultar_saldo():
    print(f"Saldo atual: R$ {saldo:.2f}")

def menu_banco():
    while True:
        print("\n=== BANCO PYTHON ===")
        print("1. Depositar")
        print("2. Sacar")
        print("3. Consultar Saldo")
        print("4. Sair")
        
        opcao = input("Escolha uma opção: ")
        
        if opcao == "1":
            depositar()
        elif opcao == "2":
            sacar()
        elif opcao == "3":
            consultar_saldo()
        elif opcao == "4":
            print("Obrigado por usar o Banco Python!")
            break
        else:
            print("Opção inválida!")

menu_banco()

Explicação linha por linha:

  • Linha 1: saldo = 0 - Variável global para armazenar saldo da conta
  • Linha 3: def depositar(): - Função para realizar depósito
  • Linha 4: global saldo - Permite modificar variável global dentro da função
  • Linha 12: def sacar(): - Função para realizar saque
  • Linha 13: global saldo - Permite modificar variável global dentro da função
  • Linha 22: def consultar_saldo(): - Função para consultar saldo atual
  • Linha 25: def menu_banco(): - Função principal que gerencia o sistema bancário
  • Linhas 26-41: Loop principal que gerencia menu e chama funções apropriadas

🎯 Parabéns! Você completou todos os exercícios de funções! Agora você domina como criar, usar e organizar funções em Python. Continue praticando e explore mais possibilidades!

6.9.5.1 Exercício 23: Calculadora de IMC com Histórico

Enunciado: Crie uma calculadora de IMC que armazene o histórico usando funções.

Resposta:

historico = []

def calcular_imc(peso, altura):
    imc = peso / (altura ** 2)
    return imc

def classificar_imc(imc):
    if imc < 18.5:
        return "Abaixo do peso"
    elif imc < 25:
        return "Peso normal"
    elif imc < 30:
        return "Sobrepeso"
    else:
        return "Obesidade"

def cadastrar_imc():
    nome = input("Digite seu nome: ")
    peso = float(input("Digite seu peso (kg): "))
    altura = float(input("Digite sua altura (m): "))
    
    imc = calcular_imc(peso, altura)
    classificacao = classificar_imc(imc)
    
    resultado = {
        "nome": nome,
        "peso": peso,
        "altura": altura,
        "imc": imc,
        "classificacao": classificacao
    }
    
    historico.append(resultado)
    
    print(f"\n{nome}: IMC {imc:.2f} - {classificacao}")

def ver_historico():
    if not historico:
        print("Nenhum cálculo realizado ainda.")
    else:
        print("\n=== HISTÓRICO ===")
        for i, resultado in enumerate(historico, 1):
            print(f"{i}. {resultado['nome']}: IMC {resultado['imc']:.2f} - {resultado['classificacao']}")

def menu_imc():
    while True:
        print("\n=== CALCULADORA DE IMC ===")
        print("1. Calcular IMC")
        print("2. Ver Histórico")
        print("3. Sair")
        
        opcao = input("Escolha uma opção: ")
        
        if opcao == "1":
            cadastrar_imc()
        elif opcao == "2":
            ver_historico()
        elif opcao == "3":
            print("Obrigado por usar a Calculadora de IMC!")
            break
        else:
            print("Opção inválida!")

menu_imc()

Explicação linha por linha:

  • Linha 1: historico = [] - Lista para armazenar histórico
  • Linha 3: def calcular_imc(peso, altura): - Função para calcular IMC
  • Linha 6: def classificar_imc(imc): - Função para classificar IMC
  • Linha 15: def cadastrar_imc(): - Função para cadastrar novo IMC
  • Linhas 16-18: Pedem dados do usuário
  • Linhas 20-21: Calculam IMC e classificação
  • Linhas 23-30: Criam dicionário com resultado
  • Linha 32: historico.append(resultado) - Adiciona ao histórico
  • Linha 36: def ver_historico(): - Função para mostrar histórico
  • Linha 44: def menu_imc(): - Função principal do menu
  • Linhas 45-58: Loop principal do sistema

6.9.5.2 Exercício 24: Sistema de Notas com Funções

Enunciado: Crie um sistema de notas usando funções para cadastrar alunos, adicionar notas e calcular médias.

Resposta:

alunos = {}

def cadastrar_aluno():
    nome = input("Digite o nome do aluno: ")
    if nome not in alunos:
        alunos[nome] = []
        print(f"Aluno {nome} cadastrado com sucesso!")
    else:
        print("Aluno já cadastrado!")

def adicionar_nota():
    nome = input("Digite o nome do aluno: ")
    if nome in alunos:
        nota = float(input("Digite a nota: "))
        if 0 <= nota <= 10:
            alunos[nome].append(nota)
            print(f"Nota {nota} adicionada para {nome}")
        else:
            print("Nota deve estar entre 0 e 10!")
    else:
        print("Aluno não encontrado!")

def calcular_media():
    nome = input("Digite o nome do aluno: ")
    if nome in alunos and alunos[nome]:
        media = sum(alunos[nome]) / len(alunos[nome])
        print(f"Média de {nome}: {media:.2f}")
    else:
        print("Aluno não encontrado ou sem notas!")

def ver_relatorio():
    print("\n=== RELATÓRIO ===")
    if alunos:
        for nome, notas in alunos.items():
            if notas:
                media = sum(notas) / len(notas)
                print(f"{nome}: {len(notas)} notas, média {media:.2f}")
            else:
                print(f"{nome}: sem notas")
    else:
        print("Nenhum aluno cadastrado!")

def menu_notas():
    while True:
        print("\n=== SISTEMA DE NOTAS ===")
        print("1. Cadastrar Aluno")
        print("2. Adicionar Nota")
        print("3. Calcular Média")
        print("4. Ver Relatório")
        print("5. Sair")
        
        opcao = input("Escolha uma opção: ")
        
        if opcao == "1":
            cadastrar_aluno()
        elif opcao == "2":
            adicionar_nota()
        elif opcao == "3":
            calcular_media()
        elif opcao == "4":
            ver_relatorio()
        elif opcao == "5":
            print("Sistema encerrado!")
            break
        else:
            print("Opção inválida!")

menu_notas()

Explicação linha por linha:

  • Linha 1: alunos = {} - Dicionário para armazenar alunos e notas
  • Linha 3: def cadastrar_aluno(): - Função para cadastrar aluno
  • Linha 11: def adicionar_nota(): - Função para adicionar nota
  • Linha 23: def calcular_media(): - Função para calcular média
  • Linha 31: def ver_relatorio(): - Função para mostrar relatório
  • Linha 42: def menu_notas(): - Função principal do menu
  • Linhas 43-58: Loop principal do sistema

6.9.5.3 Exercício 25: Sistema Bancário com Funções

Enunciado: Crie um sistema bancário usando funções para depósito, saque e consulta de saldo.

Resposta:

saldo = 0

def depositar():
    global saldo
    valor = float(input("Digite o valor do depósito: "))
    if valor > 0:
        saldo += valor
        print(f"Depósito de R$ {valor:.2f} realizado! Saldo atual: R$ {saldo:.2f}")
    else:
        print("Valor inválido!")

def sacar():
    global saldo
    valor = float(input("Digite o valor do saque: "))
    if valor > 0 and valor <= saldo:
        saldo -= valor
        print(f"Saque de R$ {valor:.2f} realizado! Saldo atual: R$ {saldo:.2f}")
    elif valor > saldo:
        print("Saldo insuficiente!")
    else:
        print("Valor inválido!")

def consultar_saldo():
    print(f"Saldo atual: R$ {saldo:.2f}")

def menu_banco():
    while True:
        print("\n=== BANCO PYTHON ===")
        print("1. Depositar")
        print("2. Sacar")
        print("3. Consultar Saldo")
        print("4. Sair")
        
        opcao = input("Escolha uma opção: ")
        
        if opcao == "1":
            depositar()
        elif opcao == "2":
            sacar()
        elif opcao == "3":
            consultar_saldo()
        elif opcao == "4":
            print("Obrigado por usar o Banco Python!")
            break
        else:
            print("Opção inválida!")

menu_banco()

Explicação linha por linha:

  • Linha 1: saldo = 0 - Variável global para armazenar saldo
  • Linha 3: def depositar(): - Função para realizar depósito
  • Linha 4: global saldo - Permite modificar variável global
  • Linha 12: def sacar(): - Função para realizar saque
  • Linha 13: global saldo - Permite modificar variável global
  • Linha 22: def consultar_saldo(): - Função para consultar saldo
  • Linha 25: def menu_banco(): - Função principal do menu
  • Linhas 26-41: Loop principal do sistema

🎯 Parabéns! Você completou todos os exercícios de funções! Agora você domina como criar, usar e organizar funções em Python. Continue praticando e explore mais possibilidades!

6.10 Resumo do Capítulo

Parabéns! Você chegou ao final do capítulo sobre Funções em Python! 🎉

6.10.1 O que você aprendeu:

  1. O que são funções - Pequenos blocos de código que fazem uma tarefa específica
  2. Como criar funções - Usando def nome_funcao():
  3. Como usar funções - Chamando-as pelo nome seguido de ()
  4. Funções com parâmetros - Passando informações para as funções
  5. Funções que retornam valores - Usando return
  6. Funções built-in - Funções que já vêm com o Python
  7. Refatoração - Melhorando código existente usando funções

6.10.2 Conceitos importantes:

  • Função: Bloco de código reutilizável
  • Parâmetro: Informação que você passa para a função
  • Argumento: Valor real que você passa
  • Retorno: Valor que a função devolve
  • Escopo: Onde uma variável pode ser usada
  • Refatoração: Melhorar código existente

6.10.3 Próximos passos:

Agora que você domina as funções, está pronto para aprender sobre Estruturas de Dados no próximo capítulo! Você vai descobrir como trabalhar com listas, dicionários e tuplas de forma eficiente.

6.10.4 Dica final:

As funções são como receitas de culinária - você escreve uma vez e pode usar sempre que precisar! Quanto mais você praticar criando funções, mais fácil será organizar seus programas.

Lembre-se: Uma boa função faz uma coisa bem feita. Se sua função está fazendo muitas coisas, considere dividi-la em funções menores!


🎉 Você completou o Capítulo 6: Funções em Python!

Continue praticando e nos vemos no próximo capítulo! 🚀

6.10.5 Respostas

1. Crie uma função que recebe três notas. Ela deve retornar a média dessas notas para o usuário.

def calcular_media(nota1, nota2, nota3):
    media = (nota1 + nota2 + nota3) / 3
    return media
    
resultado = calcular_media(8.5, 9.0, 7.1)
print(resultado)

O código acima define uma função chamada calcular_media que recebe três parâmetros: nota1, nota2 e nota3. Esses parâmetros são utilizados na função para calcular a média entre as três notas, armazenada na variável media. Em seguida, a função retorna a média calculada.

Fora da função, a média é calculada chamando a função calcular_media e passando três valores como argumentos: 8.5, 9.0 e 7.1. O resultado retornado pela função é armazenado na variável resultado. Por fim, o resultado é mostrado na tela utilizando a função print.

2. Escreva uma função que recebe como parâmetro uma temperatura em graus Celsius. Ela deve retornar a temperatura convertida para graus Fahrenheit.

def celsius_para_fahrenheit(temp_celsius):
    temp_fahrenheit = (temp_celsius * 9/5) + 32
    return temp_fahrenheit

temperatura = 0
print("A temperatura em Fahrenheit é:", celsius_para_fahrenheit(temperatura))

A função é definida com o nome celsius_para_fahrenheit e tem um parâmetro de entrada temp_celsius que representa a temperatura em graus Celsius.

Dentro da função, a temperatura em Celsius é convertida para Fahrenheit utilizando a fórmula de conversão: temp_fahrenheit = (temp_celsius * 9/5) + 32. Em seguida, a temperatura em Fahrenheit é retornada pela função com o uso da palavra-chave return.

Fora da função, a variável temperatura é inicializada com o valor 0, e em seguida a função celsius_para_fahrenheit é chamada com esse valor como argumento. O resultado da função é então impresso na tela utilizando a função print.

3. Adapte o código para que tenha uma função chamada verificar_primo em que recebe um parâmetro de entrada chamado numero e retorna True se ele for primo e False se não for primo.

def verificar_primo(numero):
    primo = True

    for i in range(2, num):
        if num % i == 0:
            primo = False
            break
            
    return primo

num = int(input("Digite um número: "))
if verificar_primo(num):
    print(num, "é um número primo")
else:
    print(num, "não é um número primo")

O código permanece bem parecido com o que estava no exemplo. A diferença é que o bloco de código responsável por determinar se um número era ou não primo encontra-se dentro da função chamada verificar_primo. Dentro dela existe toda a lógica necessária para determinar se numero é ou não primo.

Veja que o int(input("Digite um número")) está fora da função. Isto acontece porque a tarefa desta função é verificar se um número é primo ou não, como o próprio nome já diz. Como a tarefa dela não é a de solicitar números ao usuário, o int(input()) fica do lado de fora. Além disso, ela precisa de um numero para funcionar. Por isso, precisamos tê-lo em mãos antes de entrar na função.

4. Adapte o código para que tenha uma função chamada verificar_palindromo em que recebe um parâmetro de entrada chamado palavra e retorna True se ele for palíndromo e False se não for palíndromo.

def verificar_palindromo(palavra):
    i = 0
    j = len(palavra) - 1
    palindromo = True

    while i < j:
        if palavra[i] != palavra[j]:
            palindromo = False
            break
        i += 1
        j -= 1
        
    return palindromo

palavra_teste = input("Digite uma palavra: ")
eh_palindromo = verificar_palindromo(palavra_teste)

if eh_palindromo:
    print(palavra_teste, "é um palíndromo")
else:
    print(palavra_teste, "não é um palíndromo")

Aqui, a mesma lógica do exercício anterior se aplica: colocamos dentro da função o mínimo necessário para que ela funcione com o parâmetro de entrada fornecido (no caso, uma palavra). Como precisamos da palavra antes de começar, o input() que solicita uma palavra do usuário acontece fora da função. Além disso, com o resultado em mãos (e armazenado na variável eh_palindromo) conseguimos mostrar uma frase na tela. Perceba que chamei a variável com este nome (e não de palindromo) para não te confundir e, ainda, para deixar claro que as variáveis dentro de uma função não são as mesmas que estão fora.

5. Adapte o código que você fez no exercício 4 para que a função seja chamada dentro de um for. O for deve repetir cinco vezes. A cada iteração você deve pedir para que o usuário digite uma palavra. Com isso, testaremos se cinco palavras diferentes são ou não palíndromos.

def verificar_palindromo(palavra):
    i = 0
    j = len(palavra) - 1
    palindromo = True

    while i < j:
        if palavra[i] != palavra[j]:
            palindromo = False
            break
        i += 1
        j -= 1

    return palindromo

for i in range(5):
    palavra_teste = input("Digite uma palavra: ")
    eh_palindromo = verificar_palindromo(palavra_teste)

    if eh_palindromo:
        print(palavra_teste, "é um palíndromo")
    else:
        print(palavra_teste, "não é um palíndromo")

A única mudança que de fato houve foi a adição do for i in range(5):, e adicionei uma indentação em todas as linhas que vieram depois para colocá-las dentro do for. E só. Veja que conseguimos chamar esta função diferentes vezes e ela teve o mesmo funcionamento esperado (isto é, verificar se uma palavra é ou não um palíndromo) para diferentes palavras. Igualzinho quando esperamos que o print() funcione da mesma forma para frases diferentes ou quando esperamos que o input() também tenha a mesma serventia independentemente do lugar em que estamos o usando. Entende agora o objetivo por trás deste reuso das funções?

6.11 Referências bibliográficas

  • FOWLER, Martin; BECK, Kent. Refactoring: Improving the Design of Existing Code. Addison-Wesley Professional, 1999.
  • KENLON, Seth. Why you should always do documentation before development. Open Source.com, 2017. Disponível em: https://opensource.com/article/17/8/doc-driven-development. Acesso em: 12 mar. 2023.
  • PYTHON. Python Documentation: Built-in Functions. Disponível em: https://docs.python.org/3/library/functions.html#func-list. Acesso em: 12 mar. 2023.
  • PYTHON. Python Documentation: Defining Functions. Disponível em: https://docs.python.org/3/tutorial/controlflow.html#defining-functions. Acesso em: 12 mar. 2023.
  • PROGRAMIZ. Python Functions. Disponível em: https://www.programiz.com/python-programming/function. Acesso em: 12 mar. 2023.
  • TUTORIALSPOINT. Python Functions. Disponível em: https://www.tutorialspoint.com/python/python_functions.htm. Acesso em: 12 mar. 2023.
  • W3SCHOOLS. Python Functions. Disponível em: https://www.w3schools.com/python/python_functions.asp. Acesso em: 12 mar. 2023.