3
\$\begingroup\$

After a conversation with my math teacher about a base algebra (base 43 using all the algebra symbols) and finding it more than the 30 min of work I was looking for, I decided to make this instead.

import math


letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]


def print_bases(base: int, num: int) -> None:
    new_num = []
    div = num
    while div != 0:
        if len(str(div % base)) > 1:
            new_num.insert(0, letters[((div % base) - 10)])
        else:
            new_num.insert(0, str(div % base))
        div = math.floor(div / base)
    new_num = "".join(new_num)
    print(f"{num} in base {base} is {new_num}")


while True:
    while True:
        try:
            num = int(input("Please enter a number in base 10: "))
            break
        except (NameError, ValueError):
            print("Please use numbers only")
    for base in range(35):
        print_bases(base + 2, num)

As this was made for fun I forgot to add any comments (doing that is still new for me), so I hope it makes sense. My main problem is I want to know if I can get rid of letters. Also print_bases seems messy and I wonder if that can be cleaned up. Any other small fixes would be appreciated.

;)

\$\endgroup\$
2
\$\begingroup\$
  • Since letters is a list of characters (1 length strings) you logistically have made letters a string. And so you can simplify writing it as a string rather than a list of characters.

    letters = "ABCDE..."
    
  • You can remove the need to define letters by using string.ascii_uppercase.

  • It's good to see some type hints. Good job!
  • I would suggest changing your function to only take in the base and the number, and return a new number, rather than print it.
  • You don't need to use math.floor you have a couple of alternate options:

    • Use int - int(div / base).
    • Use the floordiv operator - div // base.
  • Rather than using div % base and math.floor(div / base) you can use divmod to divide and get the modulo in one command.

  • Rather than using list.insert I would recommend using list.append and then using reversed.

    This is because inserting at the start of a list in Python has to move every other item from the beginning of the list to the end of the list. Append on the other hand only needs to append to the end of the list and it doesn't have to touch the rest of the list.

    I also find it cleaner to just use .append.

  • The check len(str(div % base)) > 1 would be better described as (div % base) >= 10. This is as we're working with numbers - /, %, divmod - and so thinking of the value as a number is easier.
  • If you change letters to string.digits + string.ascii_uppercase then you can remove the need for the if.
  • I suggest you change the order of your function's arguments, so it's inline with other base conversion functions. num then base.
  • It's Pythonic to have constants be UPPER_SNAKE_CASE and so letters should be all caps.

There's a lot of points above, but for a beginner your code is good. Good job!

import string

LETTERS = string.digits + string.ascii_uppercase


def to_base(num: int, base: int) -> str:
    new_num = []
    while num != 0:
        num, mod = divmod(num, base)
        new_num.append(LETTERS[mod])
    return "".join(reversed(new_num))


while True:
    while True:
        try:
            num = int(input("Please enter a number in base 10: "))
            break
        except (NameError, ValueError):
            print("Please use numbers only")
    for base in range(2, 37):
        new_num = to_base(num, base)
        print(f"{int(new_num, base)} in base {base} is {new_num}")
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.