Displaying Output
๐จ๏ธ Displaying Output on the Screen
Every language needs a way to show something to the user, and Python's answer is a single, deceptively simple function: print(). What makes it interesting isn't the function itself โ it's the handful of different ways Python lets you build the text you hand to it. String concatenation, f-strings, and .format() all solve the same problem, but they weren't all designed at the same time, and code you'll read in the wild uses all three. Knowing which one to reach for โ and why f-strings won โ is the real subject of this lesson.
System.out.println() and no console.log() โ just print(), and it already does more than either of those by default: it accepts any number of comma-separated arguments, automatically converts each one to a string, joins them with a space, and appends a newline โ all without you asking for any of it. Java needs explicit + concatenation or String.format(); JavaScript needs template literals (`` `${x}` ``) or comma-separated console.log arguments (which โ unlike Python โ don't auto-stringify objects into readable text nearly as often). Python's f-strings, introduced in 3.6, are the closest cousin to JavaScript's template literals โ same ${expr}-style idea, different bracket ({expr}) and a mandatory f prefix.
๐งฑ The Building Blocks
print() is one function, but it has more going on under the hood than its name suggests โ and there are three genuinely different ways to assemble the string you pass to it.
str() needed) and joins them with a single space by default.sep and endsep replaces the default single-space joiner between arguments. end replaces the default trailing newline โ set it to "" to keep printing on the same line.+. Every non-string value needs an explicit str() call first โ Python won't silently convert a number for you the way print()'s own comma-separated arguments do.f, then drop any expression straight into { } โ no concatenation, no manual str(). This is the modern, preferred way to build formatted strings in Python..format() Method{} or {0}/{1} get filled in, in order, by .format()'s arguments. Still common in older codebases and library documentation.{ } introduces a mini-language for controlling exactly how a value is displayed โ decimal places, thousands separators, minimum width, and left/right/centre alignment.๐ Why Concatenation Falls Apart Fast
A single + is harmless. The problem shows up once a line needs several values mixed with text โ concatenation forces every non-string value through str() by hand, and every join point needs its own +.
item = "Notebook"
qty = 3
price = 4.5
total = qty * price
# Concatenation โ every value needs its own str() and its own +
print(item + " x" + str(qty) + " = ยฃ" + str(total))
# .format() โ placeholders filled in argument order
print("{} x{} = ยฃ{}".format(item, qty, total))
# f-string โ the value sits right where it's used, no str() needed
print(f"{item} x{qty} = ยฃ{total}")
# All three print: Notebook x3 = ยฃ13.5
๐งพ Case Study: Printing an Aligned Receipt
Format specifiers earn their keep once output needs to actually line up โ a plain f-string with no specifier leaves every price at a different width, which looks fine for one line and wrong the moment there's a second line to compare it against.
{name:<10} left-aligns name inside a 10-character field; {price:>8.2f} right-aligns price inside an 8-character field, always showing exactly two decimal places.items = [("Notebook", 4.5), ("Pen", 1.2), ("Eraser", 0.75)]
total = 0
for name, price in items:
print(f"{name:<10} ยฃ{price:>8.2f}")
total += price
print(f"{'-' * 19}")
print(f"{'Total':<10} ยฃ{total:>8.2f}")
# Notebook ยฃ 4.50
# Pen ยฃ 1.20
# Eraser ยฃ 0.75
# -------------------
# Total ยฃ 6.45
๐ Quick Reference โ Displaying Output
| Task | Syntax | Notes |
|---|---|---|
| Print several values on one line | print(a, b, c) | Auto-converts to string, joins with a space by default |
| Change the joiner between arguments | print(a, b, sep="-") | Default separator is a single space |
| Suppress the trailing newline | print(x, end="") | Default end is "\n" |
| Concatenate strings and values | "a" + str(n) | Every non-string needs an explicit str() |
| Embed an expression in a string | f"{expr}" | Preferred since Python 3.6 โ clearest, fastest to write |
| Fill positional placeholders | "{} {}".format(a, b) | Common in code written before f-strings existed |
| Fixed decimal places | f"{x:.2f}" | Rounds, doesn't truncate |
| Left / right / centre align | f"{x:<10}" / f"{x:>10}" / f"{x:^10}" | Number after the symbol is the field width |
| Zero-pad an integer | f"{n:05d}" | Pads with leading zeros to 5 total digits |
| Debug a variable quickly | f"{x=}" | 3.8+ โ prints both the expression text and its value, e.g. x=42 |
Concatenating a number with
+ raises TypeError, it doesn't silently coerce โ "Age: " + 30 crashes in Python, whereas Java happily turns "Age: " + 30 into "Age: 30" and JavaScript does the same. Python requires str(30) first, or (better) an f-string, which sidesteps the whole issue.An f-string still needs the
f prefix โ "{name}" without the leading f prints the literal text {name}, curly braces and all, instead of raising an error. This is a silent bug, not a crash, so it's easy to miss.print()'s default end is a newline, not nothing โ unlike JavaScript's process.stdout.write() or manually building a string in Java, every bare print() call adds its own line break. Forgetting this is why a loop of print(x, end="") calls without a final newline can leave your very next output glued onto the same line.Format-spec syntax is its own mini-language, not Python expressions โ
{x:>10} means "right-align in a 10-char field," not "compare x to 10." It only appears after the colon inside { }, and it isn't valid anywhere else in Python.