snippetpythonMinor
Convert between two bases, each between 2 and 36
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
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
Your check for proper string :
can easily be rewritten with an additional
Even better, you can rewrite this in a clean and efficient way using all :
Logic flow
Then, the whole
The reasons why I prefer that way to write it :
Similarly, I'd rather write
and
Reusing code
Now that we've played a bit with
Premature optimisation
Your check on
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 :
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
allYour check for proper string :
is_proper = True
for character in starting_num:
if character not in base_members:
is_proper = Falsecan 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_numsounds like a integer to me. Surprise, it is a string.
base_ten_numseems 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 thinknis usually a good enough name. Similarly,base_to_tenandten_to_basecould beint_to_stringorstring_to_int.
numberis actually a string and so isending_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 = Falseis_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.