How to fix "Valueerror: invalid literal for int() with base 10: '' - Python?

Asked

Viewed 5,809 times

1

Summary of my program/ problem: I need to draw at an ATM between 10 and 600 reais. When running the program, any value above 100 it prints correctly, but if I put any value below 100 it presents the error described below.

I have the following error in my program:

Traceback (most recent call last):
  File "f:/Formação Acadêmica/Tecnologia/Udemy/Python/estruturaDeDecisao.py", line 29, in <module>
    intUnidade = int(unidade)
ValueError: invalid literal for int() with base 10: ''

The question asks the following:

Make a program for an ATM. The program should ask the user the value of the withdrawal and indicate how many notes of each value will be provided. The available banknotes will be 1, 5, 10, 50 and 100 reais. The minimum value is 10 real and the maximum 600 real. The program should not worry about the amount of banknotes on the machine. Example 1: To withdraw the amount of 256 reais, the program provides two notes of 100, a 50 banknote, a 5 banknote and a 1 banknote; Example 2: To withdraw the amount of 399 reais, the program provides three notes of 100, a 50 banknote, four 10 banknote, a 5 banknote and four 1 banknote.


The code I built in Python is following:


print(' ')
print('-------------------------------------------------------------------------------------')
print('                           BEM VINDO AO CAIXA ELETRONICO                             ')
print('-------------------------------------------------------------------------------------')
print('  Informamos que o valor mínimo para saque é de R$ 10 reais e o máximo R$ 600 reais  ')
print('-------------------------------------------------------------------------------------')
valorSaque = int(input('  Informe o valor de saque R$ '))
print('-------------------------------------------------------------------------------------')
saqueStr = str(valorSaque)

centena = saqueStr[0:1]
intCentena = int(centena)
dezena = saqueStr[1:2]
intDezena = int(dezena)
unidade = saqueStr[2:3]
intUnidade = int(unidade)
print('O saque terá as seguintes notas: ')
print(' {} nota(s) de R$ 100!'.format(intCentena))

if intDezena == 5:        
    print(' 1 nota de R$ 50')
elif intDezena > 5:
    dezenas = intDezena - 5
    print(' 1 nota de R$ 50')
    print(' {} nota(s) de R$ 10'.format(dezenas))
elif intDezena > 0 and intDezena < 5:
    print(' {} nota(s) de R$ 10'.format(intDezena))
else:
    pass

if intUnidade == 5:       
    print(' 1 nota de R$ 5')
elif intUnidade > 5:
    unidades = intUnidade -5
    print(' 1 nota de R$ 5')
    print(' {} nota(s) de R$ 1'.format(unidades))
elif intUnidade > 0 and intUnidade < 5:
    print(' {} nota(s) de R$ 1'.format(intUnidade))
else:
    pass

What should I do to get him to accept scores? Ex.: 55, 70, 25, 90 etc.

  • In your program you are assuming that the user will always type a number with hundred, ten and unit, the correct would be to do a check before "trying to separate the numbers this way". For when the number does not have three digits the error occurs.

3 answers

5

If you want to manipulate numbers and make calculations, it’s almost always best to use mathematics. Turn numbers into strings, as suggested by another answer, may even "work", but it is not ideal (besides generally being slower - of course for small programs the difference will be insignificant and imperceptible, but keep converting from number to string, to number, to string, etc., several times, not only is slower but also more prone to errors, besides being unnecessary and in my opinion more complicated).

Anyway, since we don’t need to worry about the total amount of existing notes, just go making divisions to know the amount of notes needed, and then go discounting that amount, until it reaches zero.

For example, if the value is 260, just divide by 100 (ignoring the decimal places), we will have the number of notes of 100 (in this case, will be 2). In Python there is already one operator which makes the whole division, which is the //.

Then, as we have already taken the notes of 100, I can consider only the remainder of the value, which in this case is the rest of the division by 100 (in our example, the rest of the division of 260 by 100 is 60). Having the remaining value (60), I can do the same steps with the 50 notes (divide ignoring the decimals - will give 1 - take the rest of the division - that is 10 - and repeat the procedure for 10 notes, etc), and I do so until the value zeroes. To get the rest of the split, just use the operator %.

Another detail is that you are not checking the range of values that the exercise asks for (between 10 and 600). And if the idea is just to print the amounts of each note (at the end we will see another option to store these quantities), it would look like this (I omitted the "welcome" messages etc to focus on the algorithm itself, but of course later you can add them as desired).:

while True: # enquanto não digitar um valor válido, pede que digite novamente
    try:
        valor = int(input('Digite o valor (entre 10 e 600):'))
        if 10 <= valor <= 600:
            break # valor válido, sai do while
        # se não entrou no if acima, o valor é inválido
        print('valor deve estar entre 10 e 600')
    except ValueError: # não foi digitado um número
        print('Digite um número válido')

# todas as notas possíveis
notas = [100, 50, 10, 5, 1]

for nota in notas:
    if valor >= nota:
        qtd = valor // nota # divisão exata (sem considerar casas decimais)
        print(f'{qtd} notas de {nota}')
        valor %= nota # valor recebe o resto da divisão de valor por nota

Just that. No turning into string, see the size, take the first, second index, etc., none of that. Just good old math, and with the advantage of working for any values and any set of notes.

For example, if I wanted to include the 20s and 200s, it would be enough to change the list notas, remembering to always put the higher values first:

notas = [200, 100, 50, 20, 10, 5, 1]

If I want you to accept amounts up to 100,000, just change the if for if 10 <= valor <= 100000 (and their messages). The rest of the algorithm remains the same.

Now try changing the algorithm of the other answers to accept these cases. All right that in this particular case it is not that complicated, but it will get very repetitive code (does basically the same things with different parameters, and so can be abstracted and simplified to the loop above). Noticed how despite the code of the other answer "work", is not the ideal?


And it is also possible to give a small optimized:

for nota in notas:
    if valor >= nota:
        qtd = valor // nota
        print(f'{qtd} notas de {nota}')
        valor %= nota
        if valor == 0:
            break # se o valor zerou, sai do for

If in the middle of loop the value is zero, I no longer need to check any notes, so I can stop you with break.

Another option is to use divmod, which already returns the split result and the rest at once:

for nota in notas:
    if valor >= nota:
        qtd, valor = divmod(valor, nota)
        print(f'{qtd} nota{"" if qtd == 1 else "s"} de {nota}')
        if valor == 0:
            break # se o valor zerou, sai do for

I also put a if the more to put or not the "s" in the word "note", so the message is "1 note" if the quantity is 1, and "X notes" for X greater than 1.


Finally, it is worth remembering that the codes above only print the quantities of each note. But if you also want to store these quantities, you can use a dictionary:

quantidades = {} # guardar as quantidades de cada nota
for nota in notas:
    if valor >= nota:
        qtd, valor = divmod(valor, nota)
        quantidades[nota] = qtd
        if valor == 0:
            break # se o valor zerou, sai do for

# imprimir as quantidades
for nota, qtd in quantidades.items():
    print(f'{qtd} nota{"" if qtd == 1 else "s"} de {nota}')

In the above case I only printed the quantities, but once we have these values stored in the dictionary, we can do whatever you want with them. I think it’s better that way than having a lot of variables quantidadeNotasUm, quantidadeNotasCinco, etc. Not only because it is simpler, but also because it is more generic and works with any set of notes.

1

In addition to the way suggested by @Imonferrari, you can operate on top of valorSaque,

print(' ')
print('-------------------------------------------------------------------------------------')
print('                           BEM VINDO AO CAIXA ELETRONICO                             ')
print('-------------------------------------------------------------------------------------')
print('  Informamos que o valor mínimo para saque é de R$ 10 reais e o máximo R$ 600 reais  ')
print('-------------------------------------------------------------------------------------')
valorSaque = int(input('  Informe o valor de saque R$ '))
print('-------------------------------------------------------------------------------------')

if valorSaque < 10 or valorSaque > 600:
  print('Valor inválido')
else:
  qtdeNotasCem = valorSaque // 100
  qtdeNotasCinquenta = (valorSaque % 100) // 50
  qtdeNotasVinte = (valorSaque % 50) // 20
  qtdeNotasDez = ((valorSaque % 50) // 10) - (2 * qtdeNotasVinte)
  qtdeNotasCinco = (valorSaque % 10) // 5
  qtdeNotasDois = (valorSaque % 5) // 2
  qtdeMoedasUm = (valorSaque % 5) - (2 * qtdeNotasDois);

  print('O saque terá as seguintes notas: ')
  print('    {0:d} nota{1} de R$ 100!'.format(qtdeNotasCem, 's' if qtdeNotasCem > 1 else ''))
  print('    {0:d} nota{1} de R$ 50!'.format(qtdeNotasCinquenta, 's' if qtdeNotasCinquenta > 1 else ''))
  print('    {0:d} nota{1} de R$ 20!'.format(qtdeNotasVinte, 's' if qtdeNotasVinte > 1 else ''))
  print('    {0:d} nota{1} de R$ 10!'.format(qtdeNotasDez, 's' if qtdeNotasDez > 1 else ''))
  print('    {0:d} nota{1} de R$ 5!'.format(qtdeNotasCinco, 's' if qtdeNotasCinco > 1 else ''))
  print('    {0:d} nota{1} de R$ 2!'.format(qtdeNotasDois, 's' if qtdeNotasDois > 1 else ''))
  print('    {0:d} moeda{1} de R$ 1!'.format(qtdeMoedasUm, 's' if qtdeMoedasUm > 1 else ''))

-1


One way to solve this problem is by checking the size of the string you are receiving on saqueStr:

def check_dezena(intDezena):
    if intDezena == 5:        
        print(' 1 nota de R$ 50')
    elif intDezena > 5:
        dezenas = intDezena - 5
        print(' 1 nota de R$ 50')
        print(' {} nota(s) de R$ 10'.format(dezenas))
    elif intDezena > 0 and intDezena < 5:
        print(' {} nota(s) de R$ 10'.format(intDezena))
        
def check_unidade(intUnidade):
    if intUnidade == 5:       
        print(' 1 nota de R$ 5')
    elif intUnidade > 5:
        unidades = intUnidade -5
        print(' 1 nota de R$ 5')
        print(' {} nota(s) de R$ 1'.format(unidades))
    elif intUnidade > 0 and intUnidade < 5:
        print(' {} nota(s) de R$ 1'.format(intUnidade))
    else:
        pass


print(' ')
print('-------------------------------------------------------------------------------------')
print('                           BEM VINDO AO CAIXA ELETRÔNICO                             ')
print('-------------------------------------------------------------------------------------')
print('  Informamos que o valor mínimo para saque é de R$ 10 reais e o máximo R$ 600 reais  ')
print('-------------------------------------------------------------------------------------')
valorSaque = int(input('  Informe o valor de saque R$ '))
print('-------------------------------------------------------------------------------------')
saqueStr = str(valorSaque)

if len(saqueStr) == 1:
    unidade = int(saqueStr)
    check_unidade(unidade)

elif len(saqueStr) == 2:
    unidade = int(saqueStr[-1])
    dezena = int(saqueStr[0])
    
    check_dezena(dezena)
    check_unidade(unidade)

elif len(saqueStr) == 3:
    unidade = int(saqueStr[-1])
    dezena = int(saqueStr[-2])
    centena = int(saqueStr[0])
    
    print('O saque terá as seguintes notas: ')
    print(' {} nota(s) de R$ 100!'.format(centena))
    check_dezena(dezena)
    check_unidade(unidade)
else:
    print('Indisponível')
  • Great, thank you! If you can ask me a question, on Len(sackStr)=3, why was -2 subtracted from the ten and -1 unit? The rest I understood

  • In that part: saqueStr = str(valorSaque), you have turned the integer into a String, and to access the positions within a String you use index(Indice). -1 is the last position, -2 is the penultimate.. and so on.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.