Olá, Marcelo. Como vai?
Excelente projeto! A sua solução para a calculadora ficou fantástica e demonstra um entendimento muito maduro de várias ferramentas poderosas do Python: o uso de um dicionário como estrutura de controle (substituindo múltiplos if/elif), o tratamento robusto de exceções com blocos try/except específicos e, claro, o uso de funções anônimas com lambda.
Associar os operadores (+, -, *, /) diretamente a expressões lambda dentro de um dicionário é uma prática de mercado elegantíssima, que torna o código escalável e de fácil manutenção.
Para agregar ainda mais valor ao seu aprendizado, vale a pena analisarmos uma pequena inconsistência na validação de tipos do seu código e como podemos deixar sua calculadora ainda mais flexível.
Ajuste na validação de tipos (isinstance)
Na linha onde você faz a seguinte checagem:
if not isinstance(num1, float) or not isinstance(num2, float):
O programa verifica se os números são estritamente do tipo float. No entanto, no bloco while, você já converte as entradas do usuário usando float(input(...)). Isso significa que num1 e num2 sempre serão do tipo float ao entrarem na função, tornando essa checagem redundante.
Além disso, se no futuro você decidisse passar números inteiros diretamente para a função calculadora(5, 3, '+'), a função dispararia o erro de ValueError('informe números somente'), porque o número 5 é um int, e não um float.
Uma boa prática em Python para permitir tanto inteiros quanto decimais é passar uma tupla de tipos aceitos para o isinstance():
# Aceita tanto int (inteiros) quanto float (decimais)
if not isinstance(num1, (int, float)) or not isinstance(num2, (int, float)):
raise ValueError('informe números somente')
Expandindo o projeto: Operações com apenas um número
As funções lambda são ótimas pela sua flexibilidade. Mas o que aconteceria se você quisesse adicionar uma operação que precisa de apenas um número, como elevar um número ao quadrado ou calcular a raiz quadrada?
Para que o seu dicionário de funções lambda aceite operações com números diferentes de argumentos, você pode definir os parâmetros com valores padrão. Veja que extensão interessante para o seu projeto:
def calculadora(num1, num2, operador):
operacoes = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y,
'²': lambda x, y=None: x ** 2 # y recebe None por padrão se não for enviado
}
if operador not in operacoes:
raise ValueError('Operador inválido')
if operador == '/' and num2 == 0:
raise ZeroDivisionError('Não é possível dividir por zero')
# Se for a operação de elevar ao quadrado, passamos apenas o num1
if operador == '²':
return operacoes[operador](num1)
return operacoes[operador](num1, num2)
Seu código principal está muito bem escrito, especialmente a captura das mensagens de erro customizadas com as e no print. Continue aplicando essas boas práticas de tratamento de erros e estruturas funcionais!
Espero que possa ter lhe ajudado!