The problem occurs when one is not typed a valid number, and the conversion to float
spear one ValueError
, which closes the implementation of the programme.
The other answers are suggesting putting all the code inside one try
/except
, which would actually work. But then any error at any point in the program would loop repeat itself again from the beginning. That is, if the user has already typed almost all values and only gave error in the last one, the program would go back to the beginning and ask for all values again.
Wouldn’t it be better if he just asked to type in the information that was wrong again, and kept the rest? In this case, the approach would be a little different.
In general, you can make a loop for specific information, and only ask you to type again in case of error. A more general algorithm would be something like:
repetir enquanto não tem dados válidos:
ler o dado
converter (para número, por exemplo)
validar (se é um número mesmo, ou se o valor é um dos válidos ("s" ou "n", por exemplo))
se deu erro, volta para início do loop
se o valor é válido, sai do loop
In Python, an alternative to this would be:
def ler_valores(mensagem, mensagem_erro=None, conversao=None, valores_validos=None):
while True:
try:
dado = input(mensagem)
if conversao: # se tem conversão a ser feita
dado = conversao(dado)
if valores_validos: # se tem uma lista de valores válidos
if dado in valores_validos: # verifica se é um dos valores válidos
return dado
else:
print('Você só pode digitar um dos valores válidos:', ', '.join(map(str, valores_validos)))
else:
return dado
except ValueError:
print('digite um valor válido' if mensagem_erro is None else mensagem_erro)
Then just change your loop to use this function. When I want to read a number, the conversion is float
, and when I am reading the options (such as "C"/"B", or "S"/"N"), the conversion can be "capitalized" and the list of valid values are the respective letters. Would look like this:
tipos_validos = [ '1020', '1045', '4340', '8620' ]
while True:
print("Utilize apenas valores com ponto, e não virgula!\n")
tipo = ler_valores(f'Digite o tipo ({", ".join(map(str, tipos_validos))}): ', valores_validos=tipos_validos)
if tipo == "1020" or tipo == "1045":
material = ler_valores('Chapa (C) ou barra (B)? ', conversao=lambda s: s.upper(), valores_validos=['C', 'B'])
if material == "C": ###CALCULO CHAPA###
altura = ler_valores('ALTURA: ', conversao=float)
largura = ler_valores('LARGURA: ', conversao=float)
comprimento = ler_valores('COMPRIMENTO: ', conversao=float)
peso = round(altura * largura * comprimento * 7.85 / 1000000, 3)
print(f'\n>>>>>>>> PESO CHAPA 1020/1045: {peso} KG <<<<<<<<\n')
preço = round(peso * 7, 3)
print(f'>>>>>>>> PREÇO: R$ {preço} <<<<<<<<\n')
print('DEFINA AS DIMENSÕES FINAIS DA PEÇA') ###DIMENSOES FINAIS CHAPA 1020###
altura1 = ler_valores('ALTURA FINAL: ', conversao=float)
largura1 = ler_valores('LARGURA FINAL: ', conversao=float)
comprimento1 = ler_valores('COMPRIMENTO FINAL: ', conversao=float)
peso1 = largura1 * altura1 * comprimento1 * 7.85 / 1000000
print(f'\n>>>>>>>> PESO FINAL DA PEÇA: {peso1} KG <<<<<<<<\n')
elif material == "B": ###CALCULO BARRA###
diametro = ler_valores('DIAMETRO: ', conversao=float)
comprimento = ler_valores('COMPRIMENTO: ', conversao=float)
peso = (diametro * diametro * 3.1416 * 7.85 / 4000) * (comprimento / 1000)
print(f'\n>>>>>>>> PESO BARRA 1020/1045: {peso} KG <<<<<<<< \n') ###PESO###
preço = peso * 7
print(f'>>>>>>>> PREÇO: R$ {preço} <<<<<<<<\n') ###PREÇO###
print('DEFINA AS DIMENSÕES FINAIS DA PEÇA') ###DIMENSOES FINAIS BARRA 1020###
diametro1 = ler_valores('DIAMETRO FINAL: ', conversao=float)
comprimento1 = ler_valores('COMPRIMENTO FINAL: ', conversao=float)
peso1 = (diametro1 * diametro1 * 3.1416 * 7.85 / 4000) * (comprimento1 / 1000)
print(f'\n>>>>>>>> PESO FINAL DA PEÇA {peso1} KG <<<<<<<<\n')
tempera = ler_valores("POSSUI TEMPERA? (S/N) ", conversao=lambda s: s.upper(), valores_validos=['S', 'N'])
if tempera == "S":
custotratamento = 6.10 * peso1
print(f'\n>>>>>>>> TEMPERA: R$ {custotratamento} <<<<<<<<\n')
elif tempera == "N":
custotratamento = 0
oxidacao = ler_valores("POSSUI OXIDAÇÃO? (S/N) ", conversao=lambda s: s.upper(), valores_validos=['S', 'N']) ###OXIDAÇÃO###
if oxidacao == "S":
custooxidacao = 2 * peso1
print(f'\n>>>>>>>> OXIDAÇÃO: R$ {custooxidacao} <<<<<<<<\n')
elif oxidacao == "N":
custooxidacao = 0
print('\n')
Notice that \n
can stand on the string itself, no need to put it separately. Another detail is that print
does not return anything (technically, it always returns None
), then it makes no sense to make resultado = print(etc)
. Just do print(etc)
and ready (even because you are not using these variables resultado
for nothing, and even if I did, their value would be None
, then they are unnecessary anyway and can be removed).
One of the answers was suggesting creating a function and calling herself within the except
(before it is edited), which is a totally wrong use of recursion (which is when a function calls itself, learn more by reading here and here). Although "working", after a certain number of iterations, there may be a pile burst (already using the loop above, it can repeat as many times as you want, there won’t be this problem). Now the answer has been edited and the recursion has been removed, less badly.
Another option is to use the function ler_valores
to create more specialized versions of it. For example:
def ler_float(mensagem, mensagem_erro=None):
return ler_valores(mensagem, mensagem_erro, conversao=float)
def ler_sn(mensagem, mensagem_erro=None): # lê opção sim ou não
return ler_valores(mensagem, mensagem_erro, conversao=lambda s: s.upper(), valores_validos=['S', 'N'])
Then just do something like:
altura = ler_float('ALTURA: ')
largura = ler_float('LARGURA: ')
etc...
tempera = ler_sn("POSSUI TEMPERA? (S/N) ")
Although you can still do it:
def ler_varios_float(*mensagens):
return [ ler_float(mensagem) for mensagem in mensagens ]
...
altura, largura, comprimento = ler_varios_float('ALTURA: ', 'LARGURA: ', 'COMPRIMENTO: ')
...
altura1, largura1, comprimento1 = ler_varios_float('ALTURA FINAL: ', 'LARGURA FINAL: ', 'COMPRIMENTO FINAL: ')
etc...
The loop does not include an option to leave, so the program keeps repeating itself indefinitely. An option would be to put some value on it to get it out, something like that:
tipos_validos = [ '1020', '1045', '4340', '8620', '0' ]
while True:
print("Utilize apenas valores com ponto, e não virgula!\n")
tipo = ler_valores(f'Digite o tipo ({", ".join(map(str, tipos_validos))}) ou "0" para sair: ', valores_validos=tipos_validos)
if tipo == '0': # não precisa converter para int, é meio redundante aqui
break # digitou zero, sai do loop
if tipo == "1020" or tipo == "1045":
etc...
(I had 3 great answers so I’ll probably repeat this comment for 3, but...) What a class!! Hahaha enough new information for me to assimilate, I’ve been studying for a few days. It will take me a while to understand all the new codes that have been entered by you, but thank you very much! It has already been very enlightening. <3 Thank you for dedicating your time to help me. Hugging!
– Hopp