Build an Arithmetic Formatter Project

Hello Everyone! Sharing with you all my code for this project. Please feel free to criticize.

def arithmetic_arranger(problems, show_answers=False):
    
    items = []
    operators = []
    first_row = []
    second_row = []
    width = []
    answers = []
    answersString = ""

    if len(problems)>5:
        return'Error: Too many problems.'
    else:
        #Provides separation of each items in the problem
        for problem in problems:
            tempList = problem.split(" ")
            items.append(tempList)

    #Distributes the items and width of each problem
    for item in items:
        if item[0].isdigit() and item[2].isdigit():
            if len(item[0])>4 or len(item[2])>4:
                return 'Error: Numbers cannot be more than four digits.'
            else:
                first_row.append(item[0])
                second_row.append(item[2])
                width.append(max(len(item[0]),len(item[2]))+2)
        else:
            return 'Error: Numbers must only contain digits.'          
        
        if item[1]=="/" or item[1]=="*":
            return "Error: Operator must be '+' or '-'."
        else:
            operators.append(item[1])
    
    #Solves the problems and displays if set to True 
     
    if show_answers: 
        answersString = "\n" 
        for i in range(len(problems)): 
            answersString += str(eval(problems[i])).rjust(int(width[i])) 
            if (i<len(width)-1): 
                    answersString += "    "

    #prints first row
    counter = 0
    result = ""
    for number in first_row:
        result += number.rjust(width[counter])
        if counter<len(operators)-1:
            result = result + "    "
        counter +=1    
        
    
    #prints second row
    result2 = ""
    for i in range(len(operators)):
        result2 += operators[i] + second_row[i].rjust(width[i]-1)
        if i<len(operators)-1:
            result2 = result2 + "    "

    
    #prints third row
    dashes = ""
    for i in range(len(width)):
        
        for j in range(int(width[i])):
            dashes += "-"
        if i<len(width)-1:
            dashes = dashes + "    "


    if show_answers: #if show answer is equal to True
        return result + "\n" + result2 + "\n" + dashes + answersString
    else:
        return result + "\n" + result2 + "\n" + dashes
    

Few notes:


Defining variables far away from when they are first used. Ie. answers and answersString are not used until near the middle of function, but are defined at the top of function.


There are two naming conventions used in the code: ie. second_row and answersString are not name with the same naming convention.


Loops like:

for i in range(len(something)):
    ...

Can be replaced with a much more readable versions, which use Python’s built-in capabilities, ie.:

for item in something:
    ...

or, if both index and the item is needed:

for index, item in enumerate(something):
    ...

In the for item in items: loop, all the item indexing - item[0], item[1], item[2] - doesn’t help with readability and making it clear what these item parts actually are. In Python iterables can be unpacked and assigned to multiple variables with a single line. Ie, assuming a_and_b = ['a', 'b']:

a, b = a_and_b

Also regarding the logic in that loop - what if somebody would try to use different not-supported operator ie. like x?


Last if/else has a bit of clear repetition:

    if show_answers: #if show answer is equal to True
        return result + "\n" + result2 + "\n" + dashes + answersString
    else:
        return result + "\n" + result2 + "\n" + dashes
1 Like

Some tips:

  1. Prefer for i, item in enumerate(items): instead of counter variables.

  2. Store operators/operands in structured tuples instead of parallel lists (less chance of index mismatches).

  3. Cleaner returns:
    if show_answers:
    return “\n”.join([result, result2, dashline, answerline])
    else:
    return “\n”.join([result, result2, dashline])