Projeto Calculadora
O primeiro projeto do guia: uma calculadora que roda no terminal. Ela pede um número, a operação e outro número, mostra o resultado e pergunta se você quer fazer outra conta. A conta em si é a parte fácil: o Python já sabe somar. O desafio é fazer o programa não quebrar quando alguém divide por zero, escolhe uma operação que não existe ou digita "seis" no lugar de um número.
- Ler o teclado com input() e transformar o texto em número com float().
- Escolher a conta com if e elif e depois com match e case.
- Recusar a divisão por zero com if e else.
- Repetir tudo com while e sair com break.
- Limpar o que foi digitado com strip(), lower() e replace().
- Separar o programa em funções que devolvem valores com return.
- Não deixar o programa quebrar com try e except.
O que vamos construir
Esta é a calculadora pronta, rodando no computador da Ana. O que aparece depois dos dois-pontos de cada pergunta foi digitado por ela (o 10, o +, o s…); o resto foi o programa que escreveu:
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 10 Operação (+ - * /): + Segundo número: 5 10 + 5 = 15 Outra conta? (s/n): s Primeiro número: seis "seis" não é um número. Tente de novo. « texto no lugar de número Primeiro número: 6 Operação (+ - * /): % Operação desconhecida: % « operação que não existe Operação (+ - * /): * Segundo número: 1.5 6 * 1.5 = 9 Outra conta? (s/n): s Primeiro número: 2,5 « com vírgula também vale Operação (+ - * /): / Segundo número: 0 Não dá para dividir por zero. « divisão por zero Outra conta? (s/n): s Primeiro número: 0.1 Operação (+ - * /): + Segundo número: 0.2 0.1 + 0.2 = 0.3 Outra conta? (s/n): s Primeiro número: 10 Operação (+ - * /): / Segundo número: 3 10 / 3 = 3.333333 Outra conta? (s/n): n Até logo!
Vamos chegar lá em quatro versões. No fim de cada uma, o programa roda; cada versão acrescenta uma coisa só:
- Dois números e um operador (
input,float,if/elif). - match e a divisão por zero.
- Repetir até a pessoa sair (
while Trueebreak). - Funções e entrada validada (
def,return,try/except).
Antes de começar
Você precisa saber criar e rodar um arquivo .py (Rodando um Programa), usar variáveis e f-strings. No seu computador, crie a pasta do projeto; o arquivo vai se chamar calculadora.py:
$ mkdir -p projetos/calculadora $ cd projetos/calculadora
Em cada versão há também uma caixa Experimente, que roda Python de verdade aqui na página. Nas missões deste projeto, a caixa tem um campo Entrada, já preenchido com as respostas que o programa vai receber, uma por linha, como se alguém as digitasse (a missão diz quais são).
Antes da versão 1: o tropeço clássico
O jeito mais curto de pedir dois números e somar seria este:
print("=== Calculadora da Ana ===")
a = input("Primeiro número: ")
b = input("Segundo número: ")
print(f"{a} + {b} = {a + b}")
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 10 Segundo número: 5 10 + 5 = 105
10 + 5 = 105? Não deu erro nenhum, mas a conta está errada. O motivo: o input() sempre devolve um texto (uma str), mesmo que a pessoa tenha digitado só algarismos. Para o Python, a vale "10" e b vale "5", e o + entre dois textos junta os textos (veja Juntar e Repetir Textos): "10" + "5" é "105". Para fazer conta, é preciso converter o texto em número antes. É o primeiro passo da versão 1.
Versão 1 · Dois números e um operador
A calculadora pede o primeiro número, a operação e o segundo número. Os números passam pelo float(), que transforma o texto num número com casas decimais (um float, veja Números), porque a Ana quer fazer contas como 7.5 / 2. A operação fica como texto mesmo: "+", "-", "*" ou "/". Para escolher a conta, uma escada de if e elif.
print("=== Calculadora da Ana ===")
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
b = float(input("Segundo número: "))
if op == "+":
print(f"{a} + {b} = {a + b}")
elif op == "-":
print(f"{a} - {b} = {a - b}")
elif op == "*":
print(f"{a} * {b} = {a * b}")
elif op == "/":
print(f"{a} / {b} = {a / b}")
else:
print(f"Operação desconhecida: {op}")
| Linha | O que faz |
|---|---|
print("=== Calculadora da Ana ===") | O título, para a pessoa saber que programa está rodando. |
input("Primeiro número: ") | Mostra a pergunta e espera a pessoa digitar e apertar Enter. Devolve o que ela digitou, como texto. A pergunta termina com ": " (dois-pontos e espaço) para o que for digitado não grudar nela. |
float(…) | Converte o texto em número: "10" vira 10.0, "7.5" vira 7.5. Um input() dentro de um float(): o Python faz primeiro o de dentro (pergunta) e depois o de fora (converte). |
op = input("Operação (+ - * /): ") | A operação, sem conversão: "+" é um texto e assim fica. |
if op == "+": | "Se a operação for igual a "+"". O == compara (um = só guarda valor numa variável; veja Comparações). |
elif op == "-": | "Senão, se…": só é testado quando o if de cima deu falso. O Python testa de cima para baixo e faz só o primeiro que combinar. |
else: | Pega tudo o que não combinou com nenhum dos de cima: x, %, uma palavra qualquer. |
f"{a} + {b} = {a + b}" | Uma f-string: o que está entre chaves é calculado e entra no texto. O {a + b} faz a conta ali mesmo. |
Rodando no terminal da Ana, duas vezes:
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 10 Operação (+ - * /): + Segundo número: 5 10.0 + 5.0 = 15.0 $ python3 calculadora.py === Calculadora da Ana === Primeiro número: 7.5 Operação (+ - * /): / Segundo número: 2 7.5 / 2.0 = 3.75
Agora a conta está certa. Repare no 10.0 + 5.0 = 15.0: como os números passaram pelo float(), o Python os mostra com o .0 no fim. Está correto, só não é bonito; na versão 4 a calculadora vai mostrar 10 + 5 = 15. E uma operação que não existe cai no else:
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 3 Operação (+ - * /): x Segundo número: 4 Operação desconhecida: x
float e não int?
O int() converte para número inteiro, e recusa "7.5" (dá erro). Com float(), a calculadora aceita as duas coisas: "10" vira 10.0 e "7.5" vira 7.5. Mais em Conversão de Tipos.
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 0.1 Operação (+ - * /): + Segundo número: 0.2 0.1 + 0.2 = 0.30000000000000004
Não é defeito da calculadora nem do Python: o computador guarda os números com casas decimais em binário, e alguns, como 0.1, não têm representação exata (como 1/3 não tem em decimal: 0,3333…). Sobra um erro minúsculo na 17ª casa. Quase toda linguagem de programação dá o mesmo resultado. A aula Números explica; na versão 4, a calculadora arredonda o resultado na hora de mostrar.
Quando dá errado na versão 1
ValueError
$ python3 calculadora.py
=== Calculadora da Ana ===
Primeiro número: seis
Traceback (most recent call last):
File "/home/ana/projetos/calculadora/calculadora.py", line 2, in <module>
a = float(input("Primeiro número: "))
~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: could not convert string to float: 'seis'
Esta é a primeira mensagem de erro do projeto. Linha por linha:
- Traceback (most recent call last):
- "Rastro (a chamada mais recente por último)". O Python vai mostrar o caminho até o erro.
- File "…/calculadora.py", line 2, in <module>
- O erro aconteceu no arquivo
calculadora.py, na linha 2. O<module>quer dizer "no corpo principal do programa", fora de qualquer função. - a = float(input("Primeiro número: "))
- A linha culpada, copiada do arquivo.
- ~~~~~^^^^^^^^^^^
- O sublinhado aponta o pedaço da linha que deu erro: o
float(…)(oinputdeu certo; quem falhou foi a conversão). - ValueError: could not convert string to float: 'seis'
- O tipo do erro e a explicação: "erro de valor: não consegui converter o texto
'seis'em float". Ofloat()só entende algarismos, não números por extenso.
O programa parou ali: nem chegou a perguntar a operação. A versão 4 conserta isso com try/except. A aula Lendo uma Mensagem de Erro mostra mais tracebacks.
$ python3 calculadora.py
=== Calculadora da Ana ===
Primeiro número: 2,5
Traceback (most recent call last):
File "/home/ana/projetos/calculadora/calculadora.py", line 2, in <module>
a = float(input("Primeiro número: "))
~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: could not convert string to float: '2,5'
Em português escrevemos 2,5; no Python, o decimal é com ponto: 2.5. Para o float(), "2,5" é um texto qualquer, como "seis". Na versão 4, a calculadora troca a vírgula pelo ponto antes de converter.
ZeroDivisionError
$ python3 calculadora.py
=== Calculadora da Ana ===
Primeiro número: 1
Operação (+ - * /): /
Segundo número: 0
Traceback (most recent call last):
File "/home/ana/projetos/calculadora/calculadora.py", line 13, in <module>
print(f"{a} / {b} = {a / b}")
~~^~~
ZeroDivisionError: division by zero
Agora o erro está na linha 13, e o ^ aponta exatamente a barra de a / b. ZeroDivisionError: division by zero = "erro de divisão por zero". Na matemática, dividir por zero não tem resposta, e o Python se recusa a inventar uma: ele para o programa. A versão 2 cuida disso.
Missão (versão 1): o programa ainda não pede o segundo número e não sabe subtrair. Onde está o comentário, peça e leia b com float(input("Segundo número: ")), e acrescente um elif para a operação "-". A entrada da missão é 10, -, 4: o resultado deve ser 10.0 - 4.0 = 6.0.
print("=== Calculadora da Ana ===")
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
# peça e leia o segundo número
if op == "+":
print(f"{a} + {b} = {a + b}")
elif op == "*":
print(f"{a} * {b} = {a * b}")
elif op == "/":
print(f"{a} / {b} = {a / b}")
else:
print(f"Operação desconhecida: {op}")
print("=== Calculadora da Ana ===")
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
b = float(input("Segundo número: "))
if op == "+":
print(f"{a} + {b} = {a + b}")
elif op == "-":
print(f"{a} - {b} = {a - b}")
elif op == "*":
print(f"{a} * {b} = {a * b}")
elif op == "/":
print(f"{a} / {b} = {a / b}")
else:
print(f"Operação desconhecida: {op}")
Versão 2 · match e a divisão por zero
Duas mudanças. A primeira é só de forma: a escada de if/elif que compara a mesma variável com vários valores fica mais fácil de ler com match e case ("combinar" e "caso"). A segunda conserta um defeito: antes de dividir, a calculadora confere se o segundo número é zero.
print("=== Calculadora da Ana ===")
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
b = float(input("Segundo número: "))
match op:
case "+":
print(f"{a} + {b} = {a + b}")
case "-":
print(f"{a} - {b} = {a - b}")
case "*":
print(f"{a} * {b} = {a * b}")
case "/":
if b == 0:
print("Não dá para dividir por zero.")
else:
print(f"{a} / {b} = {a / b}")
case _:
print(f"Operação desconhecida: {op}")
- match op:
- "Compare o valor de
opcom os casos abaixo." Omatchexiste desde o Python 3.10. - case "+":
- Se
opfor"+", faz o bloco de baixo (indentado com mais 4 espaços) e pula todos os outros casos. - if b == 0:
- Dentro do caso da divisão, um
ifcomum: se o divisor for zero, avisa em vez de dividir. Um bloco pode ter qualquer coisa dentro, inclusive outroif(veja Condições Aninhadas). - case _:
- O sublinhado é o "qualquer outra coisa": combina com tudo, por isso fica por último. Faz o papel do
else.
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 1 Operação (+ - * /): / Segundo número: 0 Não dá para dividir por zero. $ python3 calculadora.py === Calculadora da Ana === Primeiro número: 9 Operação (+ - * /): - Segundo número: 12 9.0 - 12.0 = -3.0
Em vez do traceback da versão 1, uma frase que a Ana entende. Isso é prevenir o erro: o programa confere antes de fazer a conta perigosa. (A outra estratégia, tratar o erro depois que ele acontece, com try/except, aparece na versão 4.)
0 funciona com 0.0
Depois do float(), o b vale 0.0, e não 0. Mesmo assim, b == 0 dá True: o Python compara o valor dos números, não o tipo. 0.0 == 0 é verdadeiro.
case _
Se o case _: sair do programa e a Ana digitar x, nenhum caso combina e o match simplesmente não faz nada: o programa termina sem mostrar resultado nem aviso. Não é um erro para o Python (por isso não há traceback), mas para quem usa parece que a calculadora "travou calada". Sempre que os casos não cobrirem tudo, ponha um case _ no fim.
Missão (versão 2): o caso da divisão ainda divide sem olhar, e a entrada da missão (1, /, 0) derruba o programa com ZeroDivisionError. Dentro do case "/", confira se b == 0: se for, mostre Não dá para dividir por zero.; senão, faça a conta.
print("=== Calculadora da Ana ===")
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
b = float(input("Segundo número: "))
match op:
case "+":
print(f"{a} + {b} = {a + b}")
case "-":
print(f"{a} - {b} = {a - b}")
case "*":
print(f"{a} * {b} = {a * b}")
case "/":
print(f"{a} / {b} = {a / b}")
case _:
print(f"Operação desconhecida: {op}")
print("=== Calculadora da Ana ===")
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
b = float(input("Segundo número: "))
match op:
case "+":
print(f"{a} + {b} = {a + b}")
case "-":
print(f"{a} - {b} = {a - b}")
case "*":
print(f"{a} * {b} = {a * b}")
case "/":
if b == 0:
print("Não dá para dividir por zero.")
else:
print(f"{a} / {b} = {a / b}")
case _:
print(f"Operação desconhecida: {op}")
Versão 3 · Repetir até a pessoa sair
Até agora, cada conta exige rodar o programa de novo. A Ana quer fazer várias contas seguidas. A solução é colocar tudo dentro de um laço while ("enquanto") e, no fim de cada volta, perguntar se ela quer continuar.
print("=== Calculadora da Ana ===")
while True:
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
b = float(input("Segundo número: "))
match op:
case "+":
print(f"{a} + {b} = {a + b}")
case "-":
print(f"{a} - {b} = {a - b}")
case "*":
print(f"{a} * {b} = {a * b}")
case "/":
if b == 0:
print("Não dá para dividir por zero.")
else:
print(f"{a} / {b} = {a / b}")
case _:
print(f"Operação desconhecida: {op}")
continuar = input("Outra conta? (s/n): ").strip().lower()
if continuar != "s":
break
print("Até logo!")
- while True:
- "Enquanto verdadeiro": um laço que, sozinho, nunca termina. Tudo o que está indentado embaixo dele se repete. Quem decide a hora de parar é o
breaklá dentro. - (o bloco inteiro andou 4 espaços)
- As perguntas e o
matchagora estão dentro dowhile, por isso ganharam mais um nível de indentação. É a indentação que diz ao Python o que faz parte do laço (veja Sintaxe e Indentação). - input("Outra conta? (s/n): ").strip().lower()
- Três passos em fila: pergunta, tira os espaços das pontas (
strip, "aparar") e passa para minúsculas (lower, "mais baixo"). Assim,S,se" s "viram todos"s". Veja Métodos de Texto. - if continuar != "s":
- "Se a resposta for diferente de
s". Qualquer outra coisa (n,não, só Enter) encerra. - break
- "Quebrar": sai do laço na hora. O programa continua na primeira linha depois do
while(veja break e continue). - print("Até logo!")
- Fora do laço (sem indentação): roda uma vez só, quando o
breakacontece.
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 10 Operação (+ - * /): + Segundo número: 5 10.0 + 5.0 = 15.0 Outra conta? (s/n): s Primeiro número: 3 Operação (+ - * /): * Segundo número: 4 3.0 * 4.0 = 12.0 Outra conta? (s/n): S « maiúsculo também vale, graças ao lower() Primeiro número: 100 Operação (+ - * /): / Segundo número: 8 100.0 / 8.0 = 12.5 Outra conta? (s/n): n Até logo!
while True com break?
Dava para escrever while continuar == "s":, mas aí a variável continuar teria de existir antes do laço (com um continuar = "s" só para entrar na primeira volta). O while True com break no fim deixa a ordem natural: primeiro faz a conta, depois pergunta. É um padrão muito comum em programas que conversam com a pessoa.
Se a Ana desistir no meio de uma conta, ela pode apertar Ctrl+C, que interrompe qualquer programa no terminal:
$ python3 calculadora.py
=== Calculadora da Ana ===
Primeiro número: 10
Operação (+ - * /): ^CTraceback (most recent call last):
File "/home/ana/projetos/calculadora/calculadora.py", line 5, in <module>
op = input("Operação (+ - * /): ")
~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
KeyboardInterrupt
O ^C é o terminal mostrando a tecla. O Python responde com KeyboardInterrupt ("interrupção pelo teclado") e o traceback mostra em que linha o programa estava esperando: a linha 5, a pergunta da operação. Não é defeito do programa: é o jeito normal de interromper. Mas assusta quem usa; a aula try e except mostra como trocar esse traceback por um "Até logo!". (Nas caixas "Experimente", o Ctrl+C também para o programa, mas sem traceback: aparece só ^C e [programa interrompido].)
Missão (versão 3): o programa faz uma conta, pergunta "Outra conta?", mas não repete. Coloque as perguntas, o match e a pergunta "Outra conta?" dentro de um while True: (indente tudo com mais 4 espaços) e saia com break quando a resposta não for s. A entrada da missão faz 10 + 5, responde s, faz 3 * 4 e responde n.
print("=== Calculadora da Ana ===")
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
b = float(input("Segundo número: "))
match op:
case "+":
print(f"{a} + {b} = {a + b}")
case "-":
print(f"{a} - {b} = {a - b}")
case "*":
print(f"{a} * {b} = {a * b}")
case "/":
if b == 0:
print("Não dá para dividir por zero.")
else:
print(f"{a} / {b} = {a / b}")
case _:
print(f"Operação desconhecida: {op}")
continuar = input("Outra conta? (s/n): ").strip().lower()
print("Até logo!")
print("=== Calculadora da Ana ===")
while True:
a = float(input("Primeiro número: "))
op = input("Operação (+ - * /): ")
b = float(input("Segundo número: "))
match op:
case "+":
print(f"{a} + {b} = {a + b}")
case "-":
print(f"{a} - {b} = {a - b}")
case "*":
print(f"{a} * {b} = {a * b}")
case "/":
if b == 0:
print("Não dá para dividir por zero.")
else:
print(f"{a} / {b} = {a / b}")
case _:
print(f"Operação desconhecida: {op}")
continuar = input("Outra conta? (s/n): ").strip().lower()
if continuar != "s":
break
print("Até logo!")
Versão 4 · Funções e entrada validada
A versão 3 já faz várias contas, mas ainda quebra com seis, com 2,5 e com qualquer coisa que não seja número. E o programa ficou comprido: está tudo misturado num bloco só. A versão 4 resolve as duas coisas de uma vez: cada tarefa vira uma função com nome, e a função que lê números insiste até receber um número de verdade.
OPERACOES = "+-*/"
def ler_numero(pergunta):
"""Pergunta até a pessoa digitar um número; aceita vírgula ou ponto."""
while True:
texto = input(pergunta).strip()
try:
return float(texto.replace(",", "."))
except ValueError:
print(f'"{texto}" não é um número. Tente de novo.')
def ler_operacao():
"""Pergunta até a pessoa digitar uma das quatro operações."""
while True:
op = input("Operação (+ - * /): ").strip()
if len(op) == 1 and op in OPERACOES:
return op
print(f"Operação desconhecida: {op}")
def formatar(numero):
"""Mostra 15 em vez de 15.0, com no máximo 6 casas decimais."""
numero = round(numero, 6)
if numero.is_integer():
return str(int(numero))
return str(numero)
def calcular(a, op, b):
"""Faz a conta e devolve o resultado (ou None, se for dividir por zero)."""
match op:
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
if b == 0:
return None
return a / b
print("=== Calculadora da Ana ===")
while True:
a = ler_numero("Primeiro número: ")
op = ler_operacao()
b = ler_numero("Segundo número: ")
resultado = calcular(a, op, b)
if resultado is None:
print("Não dá para dividir por zero.")
else:
print(f"{formatar(a)} {op} {formatar(b)} = {formatar(resultado)}")
continuar = input("Outra conta? (s/n): ").strip().lower()
if continuar != "s":
break
print("Até logo!")
Parece muito código novo, mas o "programa principal" (do print do título até o fim) ficou mais curto e mais fácil de ler do que na versão 3: ele só chama funções com nomes que dizem o que fazem. Vamos às peças.
As funções, uma por uma
| Peça | O que faz |
|---|---|
OPERACOES = "+-*/" | As operações aceitas, num lugar só. O nome em MAIÚSCULAS é o costume do Python para um valor que não muda durante o programa (uma "constante"). |
def ler_numero(pergunta): | Cria a função ler_numero, que recebe o texto da pergunta. Assim, a mesma função serve para o primeiro e para o segundo número (veja Parâmetros e Argumentos). |
"""Pergunta até…""" | A docstring: uma frase dizendo o que a função faz. Não muda nada na execução, mas ajuda quem lê. |
texto.replace(",", ".") | Troca a vírgula pelo ponto: "2,5" vira "2.5", que o float() entende. |
try: … return float(…) | "Tente": tenta converter. Se der certo, o return devolve o número e sai da função (e, com ela, do while). |
except ValueError: | Se a conversão der o ValueError que você viu na versão 1, em vez de parar o programa o Python vem para cá: mostra o aviso, e o while True pergunta de novo. Veja try e except. |
len(op) == 1 and op in OPERACOES | A operação tem de ter um caractere e estar dentro de "+-*/". O in procura um texto dentro de outro (veja is e in). Por que o len? Veja logo abaixo. |
round(numero, 6) | Arredonda para 6 casas: 0.30000000000000004 vira 0.3. |
numero.is_integer() | "É inteiro?": True para 15.0, False para 3.75. Se for, int() tira o .0. |
def calcular(a, op, b): | Só faz a conta e devolve o resultado com return; quem mostra é o programa principal. Para a divisão por zero, devolve None ("nada", veja O Valor None). |
if resultado is None: | Confere se veio "nada". Para comparar com None, o costume é is, e não ==. |
Conferindo no modo interativo as peças novas, uma de cada vez:
$ python3
Python 3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> float("2,5".replace(",", "."))
2.5
>>> float(" 7.5 ")
7.5
>>> round(0.1 + 0.2, 6)
0.3
>>> (15.0).is_integer()
True
>>> "%" in "+-*/"
False
>>> "+-" in "+-*/"
True
>>> exit()
A última linha explica o len(op) == 1: o in, entre textos, procura um pedaço. "+-" é um pedaço de "+-*/", então daria True, e a calculadora aceitaria a "operação" +-. Exigir um caractere só fecha essa porta. (O float() já ignora espaços nas pontas, como mostra o " 7.5 "; o strip() em ler_numero serve para a mensagem de erro mostrar o texto sem eles.)
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 10 Operação (+ - * /): + Segundo número: 5 10 + 5 = 15 Outra conta? (s/n): s Primeiro número: seis "seis" não é um número. Tente de novo. Primeiro número: 6 Operação (+ - * /): % Operação desconhecida: % Operação (+ - * /): * Segundo número: 1.5 6 * 1.5 = 9 Outra conta? (s/n): s Primeiro número: 2,5 Operação (+ - * /): / Segundo número: 0 Não dá para dividir por zero. Outra conta? (s/n): s Primeiro número: 0.1 Operação (+ - * /): + Segundo número: 0.2 0.1 + 0.2 = 0.3 Outra conta? (s/n): s Primeiro número: 10 Operação (+ - * /): / Segundo número: 3 10 / 3 = 3.333333 Outra conta? (s/n): n Até logo!
É a sessão do começo da página. Tudo o que derrubava a versão 1 agora tem resposta.
NameError
Se o programa principal ficar em cima das funções (o while primeiro, os def depois), acontece isto:
$ python3 calculadora.py
=== Calculadora da Ana ===
Traceback (most recent call last):
File "/home/ana/projetos/calculadora/calculadora.py", line 4, in <module>
a = ler_numero("Primeiro número: ")
^^^^^^^^^^
NameError: name 'ler_numero' is not defined
NameError: name 'ler_numero' is not defined = "o nome ler_numero não está definido". O Python lê e executa o arquivo de cima para baixo. O def é uma instrução como outra qualquer: só depois que ela roda a função passa a existir. Quando a linha 4 chamou ler_numero, o def ainda estava lá embaixo, sem ter rodado. Como consertar: as funções primeiro, o programa principal no fim, como na versão 4.
Missão (versão 4): a função ler_numero ainda não se protege: com a entrada da missão (abc, 10, +, 5, n), o abc derruba o programa com ValueError. Coloque o return float(…) dentro de um try: e, no except ValueError:, mostre "abc" não é um número. Tente de novo. (com o texto que a pessoa digitou). O while True que já existe faz a pergunta de novo.
OPERACOES = "+-*/"
def ler_numero(pergunta):
"""Pergunta até a pessoa digitar um número; aceita vírgula ou ponto."""
while True:
texto = input(pergunta).strip()
return float(texto.replace(",", "."))
def ler_operacao():
"""Pergunta até a pessoa digitar uma das quatro operações."""
while True:
op = input("Operação (+ - * /): ").strip()
if len(op) == 1 and op in OPERACOES:
return op
print(f"Operação desconhecida: {op}")
def formatar(numero):
"""Mostra 15 em vez de 15.0, com no máximo 6 casas decimais."""
numero = round(numero, 6)
if numero.is_integer():
return str(int(numero))
return str(numero)
def calcular(a, op, b):
"""Faz a conta e devolve o resultado (ou None, se for dividir por zero)."""
match op:
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
if b == 0:
return None
return a / b
print("=== Calculadora da Ana ===")
while True:
a = ler_numero("Primeiro número: ")
op = ler_operacao()
b = ler_numero("Segundo número: ")
resultado = calcular(a, op, b)
if resultado is None:
print("Não dá para dividir por zero.")
else:
print(f"{formatar(a)} {op} {formatar(b)} = {formatar(resultado)}")
continuar = input("Outra conta? (s/n): ").strip().lower()
if continuar != "s":
break
print("Até logo!")
OPERACOES = "+-*/"
def ler_numero(pergunta):
"""Pergunta até a pessoa digitar um número; aceita vírgula ou ponto."""
while True:
texto = input(pergunta).strip()
try:
return float(texto.replace(",", "."))
except ValueError:
print(f'"{texto}" não é um número. Tente de novo.')
def ler_operacao():
"""Pergunta até a pessoa digitar uma das quatro operações."""
while True:
op = input("Operação (+ - * /): ").strip()
if len(op) == 1 and op in OPERACOES:
return op
print(f"Operação desconhecida: {op}")
def formatar(numero):
"""Mostra 15 em vez de 15.0, com no máximo 6 casas decimais."""
numero = round(numero, 6)
if numero.is_integer():
return str(int(numero))
return str(numero)
def calcular(a, op, b):
"""Faz a conta e devolve o resultado (ou None, se for dividir por zero)."""
match op:
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
if b == 0:
return None
return a / b
print("=== Calculadora da Ana ===")
while True:
a = ler_numero("Primeiro número: ")
op = ler_operacao()
b = ler_numero("Segundo número: ")
resultado = calcular(a, op, b)
if resultado is None:
print("Não dá para dividir por zero.")
else:
print(f"{formatar(a)} {op} {formatar(b)} = {formatar(resultado)}")
continuar = input("Outra conta? (s/n): ").strip().lower()
if continuar != "s":
break
print("Até logo!")
Formas diferentes de escolher a conta
A calculadora usou if/elif e depois match. Há um terceiro jeito, que você vai encontrar em programas prontos: um dicionário que liga cada símbolo a uma função. O módulo operator (da biblioteca do Python) já traz as funções das contas: operator.add soma, operator.mul multiplica, e assim por diante.
import operator
a, op, b = 10.0, "*", 3.0
# Forma 1: if/elif
if op == "+":
print("if/elif:", a + b)
elif op == "*":
print("if/elif:", a * b)
# Forma 2: match/case
match op:
case "+":
print("match:", a + b)
case "*":
print("match:", a * b)
# Forma 3: um dicionário de funções
contas = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv,
}
print("dicionário:", contas[op](a, b))
$ python3 formas.py if/elif: 30.0 match: 30.0 dicionário: 30.0
Na forma 3, contas[op] busca no dicionário a função ligada a "*" (a operator.mul), e o (a, b) logo depois a chama com os dois números.
| Forma | Quando usar |
|---|---|
if / elif | Poucas opções, ou condições diferentes entre si (op == "/" and b == 0). Funciona em qualquer versão do Python. |
match / case | Comparar uma variável com vários valores fixos. Fica limpo de ler. Precisa do Python 3.10 ou mais novo. |
| Dicionário de funções | Muitas opções que fazem coisas do mesmo formato. Acrescentar uma operação é acrescentar uma linha no dicionário. Exige já conhecer dicionários e funções. |
eval()?
Na internet você vai achar calculadoras de uma linha só: print(eval(input())). O eval() ("avaliar") executa um texto como se fosse código Python:
$ python3
Python 3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> eval("10 + 5")
15
>>> eval("2,5")
(2, 5)
>>> exit()
Parece prático, mas repare no segundo: 2,5 não deu erro nem 2.5; virou um par de números (uma tupla). E o pior: o eval() executa qualquer código que a pessoa digitar, inclusive um que apague arquivos. Nunca use eval() em algo que veio do teclado, de um arquivo ou da internet. A calculadora da Ana é mais longa, mas ela sabe exatamente o que aceita.
Desafio extra: resto e potência
A Ana quer mais duas operações: o resto da divisão (%) e a potência (**, "elevado a"), que você conhece da aula Operadores Aritméticos. O ** tem dois caracteres, então o teste len(op) == 1 and op in OPERACOES não serve mais. Com uma lista de operações, o in compara itens inteiros (e não pedaços de texto), e o len deixa de ser necessário:
OPERACOES = ["+", "-", "*", "/", "%", "**"]
Com as mudanças da missão abaixo, a Ana testou assim:
$ python3 calculadora.py === Calculadora da Ana === Primeiro número: 10 Operação (+ - * / % **): % Segundo número: 3 10 % 3 = 1 Outra conta? (s/n): s Primeiro número: 2 Operação (+ - * / % **): ** Segundo número: 10 2 ** 10 = 1024 Outra conta? (s/n): s Primeiro número: 7 Operação (+ - * / % **): % Segundo número: 0 Não dá para dividir por zero. Outra conta? (s/n): n Até logo!
O resto também é uma divisão: 7 % 0 dá o mesmo ZeroDivisionError que 7 / 0, por isso o caso "%" também confere o zero.
Desafio no editor: acrescente % e ** à calculadora. Mude três lugares: OPERACOES vira a lista ["+", "-", "*", "/", "%", "**"]; o if de ler_operacao fica só if op in OPERACOES: (e a pergunta, "Operação (+ - * / % **): "); e o match de calcular ganha case "%": (recusando o zero, como a divisão) e case "**":. Com a entrada da missão, deve aparecer 10 % 3 = 1, 2 ** 10 = 1024 e a recusa de 7 % 0.
OPERACOES = "+-*/"
def ler_numero(pergunta):
"""Pergunta até a pessoa digitar um número; aceita vírgula ou ponto."""
while True:
texto = input(pergunta).strip()
try:
return float(texto.replace(",", "."))
except ValueError:
print(f'"{texto}" não é um número. Tente de novo.')
def ler_operacao():
"""Pergunta até a pessoa digitar uma das operações."""
while True:
op = input("Operação (+ - * /): ").strip()
if len(op) == 1 and op in OPERACOES:
return op
print(f"Operação desconhecida: {op}")
def formatar(numero):
"""Mostra 15 em vez de 15.0, com no máximo 6 casas decimais."""
numero = round(numero, 6)
if numero.is_integer():
return str(int(numero))
return str(numero)
def calcular(a, op, b):
"""Faz a conta e devolve o resultado (ou None, se for dividir por zero)."""
match op:
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
if b == 0:
return None
return a / b
print("=== Calculadora da Ana ===")
while True:
a = ler_numero("Primeiro número: ")
op = ler_operacao()
b = ler_numero("Segundo número: ")
resultado = calcular(a, op, b)
if resultado is None:
print("Não dá para dividir por zero.")
else:
print(f"{formatar(a)} {op} {formatar(b)} = {formatar(resultado)}")
continuar = input("Outra conta? (s/n): ").strip().lower()
if continuar != "s":
break
print("Até logo!")
OPERACOES = ["+", "-", "*", "/", "%", "**"]
def ler_numero(pergunta):
"""Pergunta até a pessoa digitar um número; aceita vírgula ou ponto."""
while True:
texto = input(pergunta).strip()
try:
return float(texto.replace(",", "."))
except ValueError:
print(f'"{texto}" não é um número. Tente de novo.')
def ler_operacao():
"""Pergunta até a pessoa digitar uma das operações."""
while True:
op = input("Operação (+ - * / % **): ").strip()
if op in OPERACOES:
return op
print(f"Operação desconhecida: {op}")
def formatar(numero):
"""Mostra 15 em vez de 15.0, com no máximo 6 casas decimais."""
numero = round(numero, 6)
if numero.is_integer():
return str(int(numero))
return str(numero)
def calcular(a, op, b):
"""Faz a conta e devolve o resultado (ou None, se for dividir por zero)."""
match op:
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
if b == 0:
return None
return a / b
case "%":
if b == 0:
return None
return a % b
case "**":
return a ** b
print("=== Calculadora da Ana ===")
while True:
a = ler_numero("Primeiro número: ")
op = ler_operacao()
b = ler_numero("Segundo número: ")
resultado = calcular(a, op, b)
if resultado is None:
print("Não dá para dividir por zero.")
else:
print(f"{formatar(a)} {op} {formatar(b)} = {formatar(resultado)}")
continuar = input("Outra conta? (s/n): ").strip().lower()
if continuar != "s":
break
print("Até logo!")
Outras ideias para continuar sozinho: guardar cada conta numa lista e mostrar o histórico quando a Ana sair; aceitar a conta inteira numa linha só (10 + 5), separando as partes com split().
Referência rápida do projeto
| Escrita | Para que serviu |
|---|---|
float(input("…")) | Perguntar e converter o texto em número |
if / elif / else | Escolher a conta (versão 1) |
match op: / case "+": / case _: | Escolher a conta comparando uma variável com valores fixos (versão 2) |
if b == 0: | Prevenir a divisão por zero |
while True: … break | Repetir até a pessoa pedir para sair (versão 3) |
.strip().lower() | Aceitar S, s e " s " como a mesma resposta |
texto.replace(",", ".") | Aceitar o decimal com vírgula |
try: … except ValueError: | Não deixar um texto inválido derrubar o programa (versão 4) |
def / return | Separar o programa em tarefas com nome |
round(x, 6), x.is_integer(), int(x) | Mostrar 15 em vez de 15.0 e 0.3 em vez de 0.30000000000000004 |
| Sintoma | Causa provável |
|---|---|
10 + 5 = 105 | Faltou converter: o input() devolve texto, e + junta textos |
ValueError: could not convert string to float: 'seis' | O texto digitado não é um número (ou usa vírgula): trate com try/except |
ZeroDivisionError: division by zero | Divisão (ou resto) por zero: confira o divisor antes |
KeyboardInterrupt | A pessoa apertou Ctrl+C |
NameError: name 'ler_numero' is not defined | A função foi chamada antes do def (ou o nome está escrito diferente) |
| Uma operação inválida não mostra nada | Faltou o case _: no match |
Exercícios
1. A conversão
Complete para que a guarde um número, e não um texto:
2. O caso que pega o resto
Complete o caso do match que combina com qualquer operação:
3. Sair do laço
Complete a palavra que encerra o while True:
4. Sem float(), a Ana digitou 10 e 5 e a calculadora mostrou 10 + 5 = 105. Por quê?
5. Na versão 4, o que acontece quando a Ana digita seis no primeiro número?
6. Por que ler_operacao confere len(op) == 1 antes do op in OPERACOES?
Resumo
- O
input()sempre devolve texto. Para fazer conta, converta comfloat()(ouint()); sem isso,"10" + "5"dá"105". if/elifematch/caseescolhem a conta; ocase _pega o que sobrou.- A divisão por zero dá
ZeroDivisionError: previna comif b == 0. while Truecombreakrepete até a pessoa pedir para sair;.strip().lower()deixa a resposta tolerante.- Texto que não é número dá
ValueError: trate comtry/exceptdentro de um laço que pergunta de novo. - Funções com nomes claros deixam o programa principal curto. Elas precisam ser criadas (
def) antes de serem chamadas. - Nunca use
eval()no que a pessoa digita.