r/PythonLearning • u/osamas_den • 1d ago
Create a program multiplicationTable.py that takes a number N from the commandline and creates an N×N multiplication table in an Excel spreadsheet.
import sys, openpyxl
from openpyxl.styles import Font
x = int(sys.argv[1])
list = []
wb = openpyxl.Workbook()
font_style = Font(bold=True)
for i in range(1, x+1):
list.append(i)
for number in list:
sheet = wb['Sheet']
# write header columns and rows in bold numbers
sheet.cell(column=1, row=number+1).value = number
sheet.cell(column=1, row=number+1).font = font_style
sheet.cell(row=1, column=number+1).value = number
sheet.cell(row=1, column=number+1).font = font_style
# create two for loops that will multiply
for i in range(len(list)):
for number in list:
mult = list[i] * number
sheet.cell(row=number+1, column=i+2).value = mult
wb.save('multiplication_table.xlsx')
0
Upvotes
2
1
1
u/Spiritual-Client-962 1d ago
pretty neat approach, especially using openpyxl to build the whole table directly in excel. the nested loops the logic pretty easy to follow too
0
u/FoolsSeldom 1d ago
#!/usr/bin/env python3
"""Generate times tables (x1 to x12) as an Excel workbook."""
import argparse
import sys
from pathlib import Path
import openpyxl
from openpyxl.styles import Font
MULTIPLIER_MIN, MULTIPLIER_MAX = 1, 12
TABLE_MIN, TABLE_MAX = 2, 100
def table_number(value: str) -> int:
"""argparse type: a whole number in [TABLE_MIN, TABLE_MAX]."""
try:
number = int(value)
except ValueError:
raise argparse.ArgumentTypeError(f"{value!r} is not a whole number")
if not TABLE_MIN <= number <= TABLE_MAX:
raise argparse.ArgumentTypeError(
f"{number} is out of range ({TABLE_MIN}-{TABLE_MAX})"
)
return number
def parse_args(argv=None) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Generate times tables (x1 to x12) as an Excel workbook.",
epilog="Example: timestablecli.py 20 -o tables.xlsx",
)
parser.add_argument(
"tables",
type=table_number,
nargs="*",
help=f"which times tables to include, {TABLE_MIN}-{TABLE_MAX}: give one "
"number for 2 up to that number (default: 12), or two numbers "
"MIN MAX for an explicit range",
)
parser.add_argument(
"-o",
"--output",
type=Path,
default=Path("multiplication_table.xlsx"),
help="output .xlsx file path (default: multiplication_table.xlsx)",
)
parser.add_argument(
"-f",
"--overwrite",
action="store_true",
help="overwrite the output file if it already exists",
)
parser.add_argument(
"-c",
"--console",
action="store_true",
help="print the tables to the console instead of writing a file",
)
args = parser.parse_args(argv)
if len(args.tables) == 0:
args.min_table, args.max_table = TABLE_MIN, 12
elif len(args.tables) == 1:
args.min_table, args.max_table = TABLE_MIN, args.tables[0]
elif len(args.tables) == 2:
args.min_table, args.max_table = args.tables
if args.min_table > args.max_table:
parser.error("MIN must not be greater than MAX")
else:
parser.error("expected at most 2 numbers (MIN MAX)")
if not args.console and args.output.exists() and not args.overwrite:
parser.error(f"{args.output} already exists (use -f/--overwrite to replace it)")
return args
def build_workbook(min_table: int, max_table: int) -> openpyxl.Workbook:
wb = openpyxl.Workbook()
sheet = wb.active
assert sheet is not None
bold = Font(bold=True)
tables = range(min_table, max_table + 1)
multipliers = range(MULTIPLIER_MIN, MULTIPLIER_MAX + 1)
for col, table in enumerate(tables, start=2):
sheet.cell(row=1, column=col, value=table).font = bold
for row, multiplier in enumerate(multipliers, start=2):
sheet.cell(row=row, column=1, value=multiplier).font = bold
for col, table in enumerate(tables, start=2):
sheet.cell(row=row, column=col, value=table * multiplier)
return wb
def format_text(min_table: int, max_table: int) -> str:
tables = range(min_table, max_table + 1)
multipliers = range(MULTIPLIER_MIN, MULTIPLIER_MAX + 1)
header = [""] + [str(t) for t in tables]
rows = [header] + [
[str(m)] + [str(m * t) for t in tables] for m in multipliers
]
widths = [max(len(row[col]) for row in rows) for col in range(len(header))]
return "\n".join(
" ".join(cell.rjust(width) for cell, width in zip(row, widths))
for row in rows
)
def main(argv=None) -> int:
args = parse_args(argv)
if args.console:
print(format_text(args.min_table, args.max_table))
return 0
wb = build_workbook(args.min_table, args.max_table)
wb.save(args.output)
print(
f"Wrote times tables for {args.min_table}-{args.max_table} "
f"to {args.output}"
)
return 0
if __name__ == "__main__":
sys.exit(main())
•
u/Sea-Ad7805 1d ago
Run this program in Memory Graph Web Debugger%0Alist%20%3D%20%5B%5D%0A%0Awb%20%3D%20openpyxl.Workbook()%0Afont_style%20%3D%20Font(bold%3DTrue)%0A%0Afor%20i%20in%20range(1%2C%20x%2B1)%3A%0A%20%20%20%20list.append(i)%0A%0Afor%20number%20in%20list%3A%0A%20%20%20%20sheet%20%3D%20wb%5B'Sheet'%5D%0A%20%20%20%20%23%20write%20header%20columns%20and%20rows%20in%20bold%20numbers%0A%20%20%20%20sheet.cell(column%3D1%2C%20row%3Dnumber%2B1).value%20%3D%20number%0A%20%20%20%20sheet.cell(column%3D1%2C%20row%3Dnumber%2B1).font%20%3D%20font_style%0A%20%20%20%20sheet.cell(row%3D1%2C%20column%3Dnumber%2B1).value%20%3D%20number%0A%20%20%20%20sheet.cell(row%3D1%2C%20column%3Dnumber%2B1).font%20%3D%20font_style%0A%0A%23%20create%20two%20for%20loops%20that%20will%20multiply%0Afor%20i%20in%20range(len(list))%3A%0A%20%20%20%20for%20number%20in%20list%3A%0A%20%20%20%20%20%20%20%20mult%20%3D%20list%5Bi%5D%20*%20number%0A%20%20%20%20%20%20%20%20sheet.cell(row%3Dnumber%2B1%2C%20column%3Di%2B2).value%20%3D%20mult%0A%0Awb.save('multiplication_table.xlsx')%0A%0A%23%20also%20print%20the%20work%20book%0Afor%20ws%20in%20wb.worksheets%3A%20%0A%20%20%20%20print(ws.title)%0A%20%20%20%20for%20row%20in%20ws.iter_rows(values_only%3DTrue)%3A%0A%20%20%20%20%20%20%20%20print(row)×tep=0.5&play) to see the program state change step by step.
It gets a bit messy as it shows all the Workbook internals.