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

Base object to convert positive numbers into other bases (2 <= base <= 35) in Python

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

Problem

I'm fairly new to Python (this is the first thing I've done that really takes advantage of classes). This works and I'm happy with it; just looking for general advice. Especially nice would be input on my comments and how 'pythonic' the code is.

``
#import fractions #unused, on todo

class Base:

# Dicts for getting a digit from a value and a value from a digit
nums = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F', 16: 'G', 17: 'H', 18: 'I', 19: 'J', 20: 'K', 21: 'L', 22: 'M', 23: 'N', 24: 'O', 25: 'P', 26: 'Q', 27: 'R', 28: 'S', 29: 'T', 30: 'U', 31: 'V', 32: 'W', 33: 'X', 34: 'Y', 35: 'Z'}
rnums = {'6': 6, 'Y': 34, '3': 3, 'M': 22, 'C': 12, '0': 0, '7': 7, 'X': 33, '1': 1, 'D': 13, 'W': 32, '9': 9, 'V': 31, 'U': 30, 'A': 10, 'L': 21, 'F': 15, 'O': 24, '4': 4, 'J': 19, 'Z': 35, 'I': 18, '5': 5, 'T': 29, 'P': 25, '2': 2, 'E': 14, 'R': 27, 'H': 17, 'S': 28, 'N': 23, '8': 8, 'B': 11, 'Q': 26, 'K': 20, 'G': 16}

# The special bases (binary, octal, hex) have different identifiers from the pattern followed by most
sbases = {2: 'b', 8: 'o', 16: 'x'}
rsbases = {'b': 2, 'o': 8, 'x': 16}

def __init__(self, cols, base = 8, bigval = None): #cols is just a holdover; not sure what the best name for this general value would be
self.vals = {} # {column: value} dictionary
self.base = base

#can be created from an int & base, a str, a dict, or another Base object
if isinstance(cols, int) and bigval is None:
self.int_init(cols)
elif isinstance(cols, str):
if cols[0] == '0' and cols[2] == 'b': #valid string
self.baseNum_init(cols)
else:
raise ValueError('str init can only be used with a string of the form
0b`')
#self.vals = convert(int(cols)).vals
# ^Thought about this before but it shouldn't be allowed
elif isinstance(cols, dict):
self.dict_init(cols)
elif isinstance(cols, Base):
self.

Solution

You can build your data structures even easier than in Stephen's answer:

nums = dict(enumerate('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'))


You can also use the string module, so you don't even have to type out the string:

import string

num = dict(enumerate(string.digits + string.ascii_uppercase))


For the rnums, his is already as good as you can get. But you could put that functionality into a function and just call that, since you use it twice:

def invert_dict(d):
    """
    Inverts a dictionary.

    Assumes all values are hashable and unique. The responsibility for this lies
    with the caller.
    """
    return {v: k for k, v in d.items()}


In Python 2.x use d.iteritems, instead of d.items for some speed-boost. Then you can use it like this:

rnums = invert_dict(nums)
rsbases = invert_dict(sbases)


In Python, almost always if you find yourself iterating over the indices of a collection, there is a simpler way to directly iterate over the elements. Here you can use reversed:

for power in reversed(self.powers):
    # Do stuff


instead of:

for k in range(len(self.powers) - 1, 0 - 1, -1):  #counting down through self.powers
    power = self.powers[k]
    # Do stuff


You should avoid using string additions like this:

ValueError('Value in column ' + str(col) + 'greater than allowed.')


This is because, since str is immutable in Python, this involves creating one additional string (the output string) for every addition. As soon as you add many (possibly even long) strings, this becomes costly.

Instead, you can use str.format:

ValueError('Value in column {} greater than allowed.'.format(col))


And if you are using Python 3.6+, you can even take advantage of f-strings:

ValueError(f'Value in column {col} greater than allowed.')


This applies in many other places as well. For example here:

class Base:
    ...
    def __repr__(self):
        return "Base('" + self.__str__() + "')"
        # b/c of str_init, eval(repr(Base)) == Base


This could be:

class Base:
    ...
    def __repr__(self):
        return "{}('{}')".format(self.__class__.__name__, self)
        # b/c of str_init, eval(repr(Base)) == Base


because format calls the __str__ method by default (you can also choose by using {!s} or {!r} for __str__ and __repr__, respectively).

Code Snippets

nums = dict(enumerate('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'))
import string

num = dict(enumerate(string.digits + string.ascii_uppercase))
def invert_dict(d):
    """
    Inverts a dictionary.

    Assumes all values are hashable and unique. The responsibility for this lies
    with the caller.
    """
    return {v: k for k, v in d.items()}
rnums = invert_dict(nums)
rsbases = invert_dict(sbases)
for power in reversed(self.powers):
    # Do stuff

Context

StackExchange Code Review Q#158444, answer score: 3

Revisions (0)

No revisions yet.