Your CLI tool outputs results. Nobody wants to read a raw dict in their terminal. What's the minimum viable table — no library, just str.join and string multiplication?
A header row, a separator line the same width, and the data rows. Each column separated by something visible like |.
Exactly. Three building blocks. First the header row with " | ".join(headers). Then a separator sized to match:
header_row = " | ".join(headers)
separator = "-" * len(header_row)"-" * n repeats the string n times — a classic Python trick. The separator ends up exactly as wide as the header, no manual counting.
And the data rows? Same pattern?
Same pattern, inside a comprehension. str(cell) for each cell guards against mixed types — if a row contains an int, join would raise without the coercion:
body = [" | ".join(str(cell) for cell in row) for row in rows]
print("\n".join([header_row, separator] + body))Four expressions. Header, separator, body comprehension, final newline-join.
Why str(cell) and not trust join to handle it?
str.join requires every element to already be a string. Pass a list containing an integer and it raises TypeError. The generator expression str(cell) for cell in row coerces each one before join sees it — one extra token, zero runtime cost.
No rows? The concatenation still works because [header_row, separator] + [] is just the header and the separator. The function never needs a zero-case guard.
Correct. Every primitive composes cleanly with empty inputs. The function stays four lines and handles every shape — headers only, one row, fifty rows — without a special case.
TL;DR: " | ".join(...) + "-" * n + "\n".join(...) is the whole recipe.
sep.join(xs) — separator between items, never trailing"-" * n — n-char divider, no magic numbersstr(cell) for cell in row — coerce mixed types before join| Line | Built from |
|---|---|
| header | `" |
| separator | "-" * len(header) |
| data rows | `[" |
| final string | "\n".join([header, sep] + data) |
Your CLI tool outputs results. Nobody wants to read a raw dict in their terminal. What's the minimum viable table — no library, just str.join and string multiplication?
A header row, a separator line the same width, and the data rows. Each column separated by something visible like |.
Exactly. Three building blocks. First the header row with " | ".join(headers). Then a separator sized to match:
header_row = " | ".join(headers)
separator = "-" * len(header_row)"-" * n repeats the string n times — a classic Python trick. The separator ends up exactly as wide as the header, no manual counting.
And the data rows? Same pattern?
Same pattern, inside a comprehension. str(cell) for each cell guards against mixed types — if a row contains an int, join would raise without the coercion:
body = [" | ".join(str(cell) for cell in row) for row in rows]
print("\n".join([header_row, separator] + body))Four expressions. Header, separator, body comprehension, final newline-join.
Why str(cell) and not trust join to handle it?
str.join requires every element to already be a string. Pass a list containing an integer and it raises TypeError. The generator expression str(cell) for cell in row coerces each one before join sees it — one extra token, zero runtime cost.
No rows? The concatenation still works because [header_row, separator] + [] is just the header and the separator. The function never needs a zero-case guard.
Correct. Every primitive composes cleanly with empty inputs. The function stays four lines and handles every shape — headers only, one row, fifty rows — without a special case.
TL;DR: " | ".join(...) + "-" * n + "\n".join(...) is the whole recipe.
sep.join(xs) — separator between items, never trailing"-" * n — n-char divider, no magic numbersstr(cell) for cell in row — coerce mixed types before join| Line | Built from |
|---|---|
| header | `" |
| separator | "-" * len(header) |
| data rows | `[" |
| final string | "\n".join([header, sep] + data) |
Write `render_table(rows, headers)` that returns a string: first line is headers joined by `" | "`, second line is `"-" * len(header_row)`, then each row of cells joined by `" | "`. Coerce cells with `str()`. Final output joined by `"\n"`.
Tap each step for scaffolded hints.
No blank-editor panic.