HiveBrain v1.2.0
Get Started
← Back to all entries
snippetpythonMinor

Convert between two bases, each between 2 and 36

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
eachbasesconverttwobetweenand

Problem

I'm doing some Python practice for fun and I wrote some code that converts between two bases. I'm thinking about expanding on this later, so the docstrings are pretty redundant from function to function.

Is this too much? Is there a way to make the documentation more clear or are there parts that I could just the let code speak for itself? Are there variables that could have been named better? Is the formatting okay? Is the way I split up the functions too disorganized? I'm assuming there are plenty of code optimizations here, but I haven't been coding too long, so I'm still getting a feel for a lot of formatting conventions as well.

```
def base_to_base(starting_base, starting_num, ending_base):
""" Takes a number of a base between base 2 and 36 and converts it to
another number of a base within the same constrictions. Starting_base and
ending_base are taken as integers and starting_num is taken as a string (as
to handle alpha characters). The initial number is converted from the starting
base to base ten and that number is then converted to the ending base.
Returns the ending number as a string. Bases larger than 10 are handled with
capital letters. Negative numbers and decimals are not handled. """
# prevents unnecessary conversion
if starting_base == 10:
base_ten_num = int(starting_num)
else:
base_ten_num = base_to_ten(starting_num, starting_base)

# prevents unnecessary conversion and returns result
if ending_base == 10:
return str(base_ten_num)
else:
return ten_to_base(base_ten_num, ending_base)

def base_to_ten(number, base):
""" Takes a number of a base between base 2 and 36 and converts it to
base 10. Number is taken as a string (as to handle alpha characters) and
base is taken as an integer. The initial number is converted from its base
to base ten and returned as an integer. Bases larger than 10 are handled
with capital letters. Negative numbers and

Solution

Using all

Your check for proper string :

is_proper = True
for character in starting_num:
    if character not in base_members:
        is_proper = False


can easily be rewritten with an additional break as there is not point in continuing once you've set is_proper to False.

Even better, you can rewrite this in a clean and efficient way using all :

is_proper = all(c in base_members for c in starting_num)


Logic flow

Then, the whole get_starting_num function can be rewritten :

def get_starting_num(starting_base):
    """ Input and verification of starting number, that it is a positive integer
    using only characters from its base. Returns starting_num as a string."""
    # Assigns string which only contains characters from the given base
    base_members = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[0:starting_base]

    while True:
        starting_num = input("starting number: ")
        if all(c in base_members for c in starting_num):
            return starting_num
        print("Please only use characters in your base (Capital letters for " +
              "bases larger than than 10)")


The reasons why I prefer that way to write it :

  • we ask the user in a consistent way : the same line of code is used every time



  • we check for validity in a single place



  • it is easy that we will return only when we get a valid string.



Similarly, I'd rather write get_starting_base:

def get_starting_base():
    """ Input and verification of starting base, that it is a positive integer
    between 2 and 36. Returns starting_base as an integer."""
    while True:
        starting_base = input("starting base: ")
        if starting_base.isdigit() and 1 < int(starting_base) < 37:
            return int(starting_base)
        print("Please enter a positive integer between 2 and 36")


and get_ending_base:

def get_ending_base():
    """ Input and verification of ending base, that it is a positive integer
    between 2 and 36. Returns ending_base as an integer."""
    while True:
        ending_base = input("ending base: ")
        if ending_base.isdigit() and 1 < int(ending_base) < 37:
            return int(ending_base)
        print("Please enter a positive integer between 2 and 36")


Reusing code

Now that we've played a bit with get_(starting|ending)_base, we notice that they look very similar. It might be worth writing a more generic function to handle this :

def get_integer_in_range(prompt, mini, maxi):
    while True:
        starting_base = input(prompt)
        if starting_base.isdigit() and mini <= int(starting_base) <= maxi:
            return int(starting_base)
        print("Please enter a positive integer between %d and %d" % (mini, maxi))

def get_starting_base():
    return get_integer_in_range("starting base: ", 2, 36)

def get_ending_base():
    return get_integer_in_range("ending base: ", 2, 36)


Premature optimisation

Your check on if starting/ending_base == 10: makes your code more complicated and adds little.
Also, it makes testing akward as it bypasses pretty much the only case I can check without any electronic device.

Naming

A few things are not that great in the naming of your functions and variables especially because it does not convey much information about the actual type of the data we are handling :

  • starting_num sounds like a integer to me. Surprise, it is a string.



  • base_ten_num seems to be a string representation of the number in base 10. It is not, it is actually an integer (the fact that it is in base 10 is irrelevant and actually wrong as it is probably not how it is stored internally). I think n is usually a good enough name. Similarly, base_to_ten and ten_to_base could be int_to_string or string_to_int.



  • number is actually a string and so is ending_num.



At this point, the code looks like :

```
def base_to_base(starting_base, string, ending_base):
""" Takes a number of a base between base 2 and 36 and converts it to
another number of a base within the same constrictions. Starting_base and
ending_base are taken as integers and starting_num is taken as a string (as
to handle alpha characters). The initial number is converted from the starting
base to base ten and that number is then converted to the ending base.
Returns the ending number as a string. Bases larger than 10 are handled with
capital letters. Negative numbers and decimals are not handled. """
n = string_to_int(string, starting_base)
return int_to_string(n, ending_base)

def string_to_int(string, base):
""" Takes a number of a base between base 2 and 36 and converts it to
base 10. Number is taken as a string (as to handle alpha characters) and
base is taken as an integer. The initial number is converted from its base
to base ten and returned as an integer. Bases larger than 10 are handled
with capital letters. Negative numbers and decimals are not handled. """
# initial

Code Snippets

is_proper = True
for character in starting_num:
    if character not in base_members:
        is_proper = False
is_proper = all(c in base_members for c in starting_num)
def get_starting_num(starting_base):
    """ Input and verification of starting number, that it is a positive integer
    using only characters from its base. Returns starting_num as a string."""
    # Assigns string which only contains characters from the given base
    base_members = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[0:starting_base]

    while True:
        starting_num = input("starting number: ")
        if all(c in base_members for c in starting_num):
            return starting_num
        print("Please only use characters in your base (Capital letters for " +
              "bases larger than than 10)")
def get_starting_base():
    """ Input and verification of starting base, that it is a positive integer
    between 2 and 36. Returns starting_base as an integer."""
    while True:
        starting_base = input("starting base: ")
        if starting_base.isdigit() and 1 < int(starting_base) < 37:
            return int(starting_base)
        print("Please enter a positive integer between 2 and 36")
def get_ending_base():
    """ Input and verification of ending base, that it is a positive integer
    between 2 and 36. Returns ending_base as an integer."""
    while True:
        ending_base = input("ending base: ")
        if ending_base.isdigit() and 1 < int(ending_base) < 37:
            return int(ending_base)
        print("Please enter a positive integer between 2 and 36")

Context

StackExchange Code Review Q#67599, answer score: 2

Revisions (0)

No revisions yet.