I've made a small function to output a multiplication grid (those things from primary school! :P) to an inputted number.

def make_grid(max):
    max += 1  # so the for loops go up to the desired number, inclusive
    print('X\t' + '\t'.join([str(_) for _ in range(max)]) + '\n')  # print all the numbers hoizontally
    for i in range(max):
        print(i, end="\t")  # print the vertical column of base numbers
        for x in range(max):
            print(str(i*x), end="\t")  # multiply the two numbers

if __name__ == "__main__":
        max = int(input("Max Number? "))
    except ValueError:
        print("Please enter a number!")

Choosing a max number of 5 (make_grid(5)) would output:

X 0   1   2   3   4   5

0 0   0   0   0   0   0   

1 0   1   2   3   4   5   

2 0   2   4   6   8   10  

3 0   3   6   9   12  15  

4 0   4   8   12  16  20  

5 0   5   10  15  20  25

I'm looking for any improvements I could make, especially the \t's - as I use them to line up the numbers, but the gap gets pretty big, unnecessarily.


2 Answers 2


make_grid() isn't quite the right name for this function, as it is printing a grid rather than returning a grid. I think you would be better off returning a long string to be printed.

In your list comprehension, _ is a bad choice for the iteration variable name, since _ indicates a throwaway value, by convention. If you then call str(_), you should pick a different name.

Besides the excessively wide spacing as you have observed, using tabs is problematic because the output would be better with the entries right-aligned. You also have a superfluous tab at the end of each line (except the header row).

Suggested solution

Use '{0:>{width}}'.format(…) to print the entries right-aligned with a fixed width.

def multiplication_grid(max):
    max += 1    # Inclusive upper bound for ranges
    grid = [['X'] + [j for j in range(max)]] + \
             [[i] + [i * j for j in range(max)] for i in range(max)]

    # Use fixed-width right alignment for every entry in the 2D grid
    width = 2 + len(str(max * max))
    fmt = lambda n: '{0:>{width}}'.format(n, width=width)
    return '\n\n'.join(''.join(fmt(entry) for entry in row) for row in grid)

[['X'] + [j for j in range(max)]] creates the header row.

[[i] + [i * j for j in range(max)] for i in range(max)] is a nested list comprehension to create the rest of the rows, where i is the row number and j is the column number.

lambda is a way to define very simple functions that do nothing more than returning an expression. The lambda could also have been written as:

    def fmt(n):
        return '{0:>{width}}'.format(n, width=width)

The last line applies fmt() to every entry in the two-dimensional grid and joins everything into a single string.


Your code is ok, but make_grid does not only make a grid, it also prints it nicely.

Remember, one function, one task.

I would use two functions:

def make_grid(limit):
    return [[i * j for i in range(limit)] for j in range(limit)]

make_grid just builds a grid as a list of lists of numbers, the way the computer likes it. We may use this output as the input to a variety of other functions.

def print_numeric_grid(grid, spacing):
    for line in grid:
        print(''.join(' ' * (spacing - len(str(i))) + str(i) for i in line))

print_numeric_grid has an easy job, the grid already exists so printing it is a piece of cake. Most of the logic is to indent it all nicely, without that the code would be even simpler.

  • \$\begingroup\$ Thanks +1 :) How does the indenting logic work? And what is the spacing parameter? \$\endgroup\$ Commented Oct 30, 2015 at 22:11
  • 1
    \$\begingroup\$ @ᔕᖺᘎᕊ Spacing indicates the number of spaces between numbers. Indenting logic is just a subtraction \$\endgroup\$
    – Caridorc
    Commented Oct 31, 2015 at 9:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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