How do you escape this while loop?

Viewed 115

I'm currently in year 10 (9th grade) and I'm making a program for school that converts binary numbers into decimal numbers and vice versa on python. My coding knowledge isn't great so the program may not be as efficient as it can be so please bear with me.

The code below is checking whether the user input only contains 1's and 0's and that it does not go over the maximum of 8 bits. When I run it and input an invalid number, it works and loops just fine but when I input a valid number, it keeps on going back to the input command and asks me to input something instead of escaping the loop and moving onto the next thing. Please help!

max_8bits = 1
only_bin = 1
while max_8bits > 0 or only_bin > 0:

    b2d_num = input("Enter a binary number:")

    for i in range(len(b2d_num)):
        if b2d_num[i] == "0" or b2d_num[i] == "1":
            if i == len(b2d_num):
                only_bin -= 1
        else:
            print("Only enter a binary number! (0's and 1's)")
            break

    if len(b2d_num) > 8:
        print("Only enter up to 8 bits!")
    elif len(b2d_num) <= 8:
        max_8bits -= 1
4 Answers

The condition i == len(b2d_num) is never True because the last loop iteration is with i == len(b2d_num) - 1.

E.g.

>>> for i in range(10):
       pass

>>> print(i)
9

The major problem is that you never set your flags to exit the loop. You never get to the point of having an index 8 in a loop that goes 0-7. When you break out of the for loop, you aren't properly managing the values. Suggestions:

  1. Use Booleans, not integers: that's the logic in your head.
  2. Simplify the value checking: use built-in Python functions.

Code:

too_long = True
not_bin = True

while too_long or not_bin:

    b2d_num = input("Enter a binary number:")

    # Check input length
    too_long = len(b2d_num) > 8
    if too_long:
        print("Only enter up to 8 bits!")
        continue

    # Check input content
    not_bin = False

    for i, bit in enumerate(b2d_num):
        not_bin = not_bin or bit not in "01"

    if not_bin:
        print("Only enter a binary number! (0's and 1's)")

The condition if i == len(b2d_num): will never be met because the range() operator does not include the stop value, so the last value of i will be len(b2d_num) - 1.


The Python language aims to be very readable, and you could improve your code using bool instead of int. This could be an improvement:

max_8bits = False
only_bin = False

while not (max_8bits and only_bin):
    b2d_num = input("Enter a binary number:")
    max_8bits = True
    only_bin = True

    # test first condition
    if len(b2d_num) > 8:
        max_8bits = False
        print("Only enter up to 8 bits!")

    # test second condition, but only if first condition is met
    if max_8bits:
        for char in b2d_num:
            if char not in ("0", "1"):
                only_bin = False
                print("Only enter a binary number! (0's and 1's)")
                break

You mentioned in a comment, that you are hesitant about for-loops that iterate over elements instead of using positional access. They are quite a bit faster than positional access. Here is a comparisson:

>>> import timeit

>>> timeit.timeit('for elem in elem_list: _ = elem', 'elem_list = list(range(1000))', number=100000)
0.9983139920514077
>>> timeit.timeit('for i in range(len(elem_list)): _ = elem_list[i]', 'elem_list = list(range(1000))', number=100000)
3.1029140750179067

>>> timeit.timeit('for elem in elem_list: _ = elem', 'elem_list = list(range(10))', number=100000)
0.014086865936405957
>>> timeit.timeit('for i in range(len(elem_list)): _ = elem_list[i]', 'elem_list = list(range(10))', number=100000)
0.06772643199656159

As you can see, using positional access to the elements of the list cause the loop to take about 3x as long (this may vary, but it is a strong indicator). Using for elem in elem_list is more readable and faster.

It appears that you have the code b2d_num = input("Enter a binary number:") inside your while loop, which will cause that code to run everytime the while loop runs.

The fix for this is quite simple, put that piece of code just above the while loop, so it will only be executed once.

Related