Skip to content

Output and input

Two tools you will use from the very first line you write: print() shows values in the terminal, input() gets text from the user. They are simple, but knowing how they behave saves you from a handful of surprises early on.

print() and input() are Python's standard terminal I/O functions. Both are more configurable than they first appear. print() accepts arguments that control how values are joined and where output ends. input() always returns a string, which shapes how you handle every value that comes from a user.

print() wraps sys.stdout; input() wraps sys.stdin. Both work exclusively with text, delegate encoding to the stream's codec, and buffer output by default. The separation of stdout from stderr, and control over flushing, both matter in real programs.

How Python runs your code

Python runs your code from top to bottom, one line at a time, in exactly the order you wrote it. No jumping around. The order you write things is the order they run. Always.

python
city = "Tokyo"
print(city)
print("Population: 14 million")

city gets assigned first. The first print runs. The second print runs. Every time, in that order.

This matters because you cannot use a variable before you have assigned it. Python has not seen it yet and will raise an error:

python
print(country)   # NameError: country is not defined yet
country = "Japan"

Keep this in mind as your programs grow: anything you use must be defined before you use it.

Python uses sequential execution: each statement is evaluated as it is encountered, in a single top-to-bottom pass through the file. There is no pre-scan of the whole file first. Referencing a name before it is assigned raises NameError at exactly that line, not earlier.

python
city = "Tokyo"
print(city)             # works: city is already bound
print(country)          # NameError: not yet assigned
country = "Japan"

The rule is simple: dependencies must be defined before the line that uses them.

Python's execution model is single-pass sequential evaluation. Name resolution happens at the point of evaluation, not at parse time. The parser builds bytecode without resolving names, which is why NameError is a runtime exception rather than a syntax error. Python has no hoisting (unlike JavaScript's var) and no forward declarations (unlike C). A name is available the moment it is bound; before that, any reference raises.

python
print(country)   # NameError at runtime, not a syntax error
country = "Japan"

Printing output

print() is how Python talks back to you. Pass it any value and it displays that value. It converts whatever you give it to text automatically.

print() converts each argument to a string via str(), joins them with a separator (a space by default), then writes the result followed by a newline to standard output. Understanding the defaults makes the optional arguments easier to reason about.

print()'s full signature is print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False). The *objects collector accepts any number of positional arguments and calls str() on each. sep and end control formatting; file redirects output to any writable stream; flush forces the buffer to drain immediately.

python
print("Hello")    # Hello
print(42)         # 42
print(3.14)       # 3.14
print(True)       # True

Multiple values

You can print multiple values at once by separating them with commas. Python puts a space between them by default. Change the separator with sep:

Multiple positional arguments are each converted with str() individually, then joined by sep. The default sep is a single space. Overriding it lets you produce formatted output without string concatenation:

Each positional argument is passed through str() individually before joining. The join uses sep, then end is appended, and the whole thing is written in a single call to the output stream. Overriding sep is cleaner than building the string manually:

python
name = "Alice"
age  = 28
print(name, age)                        # Alice 28
print("Name:", name)                    # Name: Alice
print("2024", "01", "15", sep="-")     # 2024-01-15
print("a", "b", "c", sep=", ")         # a, b, c

Controlling the line ending

Each print() call ends with a newline by default, so the next output starts on a fresh line. Change that with end. Setting end="" makes the next print continue on the same line:

The end parameter replaces the default newline. Set it to "" to suppress the line break, to " " to stay on the same line with a space, or to any other string. Combined with sep, you can produce most output formats without building strings manually:

sep and end are keyword-only arguments with defaults ' ' and '\n'. Setting end="" is the standard way to print a partial line and let the next call continue it. For real-time output such as progress indicators or logs, flush=True forces the buffer to drain immediately rather than waiting for a newline or buffer fill.

python
print("Loading", end="")
print("...")
# Loading...

print("one", end=" | ")
print("two", end=" | ")
print("three")
# one | two | three

Formatting output with f-strings

The cleanest way to build messages is f-strings. Put f before the opening quote, then wrap any variable or expression in curly braces. Python fills it in at runtime. You can put any value, calculation, or method call inside the {}.

f-strings evaluate any expression inside {} at runtime and embed the result as a string. A colon after the value introduces a format spec: a compact syntax for controlling decimal places, alignment, and number formatting. They are faster and more readable than concatenation, and they do not require explicit str() calls.

f-strings (PEP 498) compile each {} to bytecode that calls format(value, spec), which delegates to value.__format__(spec). Any class implementing __format__ controls its own display inside an f-string. Conversion flags !r, !s, !a apply repr(), str(), or ascii() before the format call. !r is the most useful: it shows quotes around strings and makes invisible characters visible.

python
name  = "Alice"
score = 980

# concatenation: clunky, requires str() for numbers
print("Player: " + name + ", Score: " + str(score))

# f-string: readable, no manual conversion
print(f"Player: {name}, Score: {score}")

You can put any expression inside {}: arithmetic, method calls, format specs:

python
price = 49.99
tax   = 0.2
total = price * (1 + tax)

print(f"Total: {total:.2f}")          # Total: 59.99
print(f"Name: {name.upper()}")        # Name: ALICE
print(f"2 + 2 = {2 + 2}")             # 2 + 2 = 4

The format spec after : controls how the value is displayed:

python
ratio = 0.8765
count = 1234567
label = "revenue"

print(f"{ratio:.1%}")       # 87.7%
print(f"{count:,}")         # 1,234,567
print(f"{label:>12}")       # "     revenue"

:.2f means "two decimal places". You will use it constantly for prices and measurements. Everything else is there when you need it. The main thing: anything can go inside {}, not just variable names.

:.2f and :.0% cover most formatting needs. The alignment specifiers (>, <, ^) with a width produce neat tabular output. The general pattern is {value:[align][width][.precision][type]}. Once you recognise the parts, any spec is readable without memorising all combinations.

The spec string is passed verbatim to value.__format__(spec). Built-in types implement the format mini-language in C. Custom classes can define __format__ to accept arbitrary spec strings. !r calls repr() before formatting: f"{name!r}" turns a string with trailing whitespace into a quoted repr, making invisible characters visible. Use it whenever a variable's value looks wrong and you need to see exactly what is in it.

Getting input from the user

input() pauses your program and waits for the user to type something. Whatever they type (and press Enter on) comes back as the return value. The string in the parentheses is the prompt the user sees.

python
name = input("What's your name? ")
print(f"Hello, {name}!")

input() always returns a string, no matter what the user types. Type 42 and you get back "42", not the number 42. To do arithmetic with it, convert explicitly:

python
age = int(input("How old are you? "))
print(f"In ten years you'll be {age + 10}.")

What if the user types something that cannot be converted? Python raises a ValueError. Handling that properly is covered in the Files and exceptions chapter.

input() writes the prompt to standard output, reads a line from standard input, strips the trailing newline, and returns the result as a string. There is no type inference. Everything from the terminal arrives as text; you declare what type you need by converting explicitly at the boundary.

python
name = input("What's your name? ")
age  = int(input("How old are you? "))

This pattern (receive text, convert to the type you need) applies everywhere external data arrives. int(), float(), and str() are the conversion tools. If the string cannot be converted, Python raises ValueError, covered in the Files and exceptions chapter.

input() is a thin interface: it calls sys.stdout.write(prompt), flushes stdout, reads one line from sys.stdin, strips the trailing newline, and returns the result as str. The return is always str by design: Python has no way to infer whether "42" was intended as an integer, a float, or literal characters. Type conversion at the boundary is explicit. This is a fundamental pattern in Python I/O: all external data arrives as text, and your code declares the type at the entry point.

python
name  = input("Enter your name: ")
score = float(input("Enter your score (0.0 to 1.0): "))

print(f"Name:  {name!r}")      # !r reveals any invisible whitespace
print(f"Score: {score:.1%}")

Writing to stderr

By default, print() writes to standard output: the stream that appears in the terminal and flows into pipes. Python also has standard error, a separate stream for diagnostics and warnings. They look identical in a terminal but are distinct: when you pipe a script's output into another command, only stdout goes through. Stderr always reaches the terminal.

Writing to stderr uses print()'s file argument. That requires importing sys, which is covered in the Modules chapter. For now, knowing the two streams exist and why they are separate is enough.

In practice

A quiz that personalises itself from user input:

python
name    = input("What's your name? ")
subject = input("Which subject? ")

print(f"Okay, {name}. Starting your {subject} quiz.")
print("Good luck!")

Both inputs come back as strings and go directly into the f-strings. No conversion needed because you are using them as text, not numbers.

A temperature converter with aligned tabular output:

python
celsius    = float(input("Temperature in Celsius: "))
fahrenheit = celsius * 9 / 5 + 32

print(f"{'Celsius':>12} {'Fahrenheit':>12}")
print(f"{celsius:>12.1f} {fahrenheit:>12.1f}")

float() handles both integers and decimals from the user. The >12 spec keeps columns aligned regardless of how many digits the numbers have. Try entering 100 and -40: the output stays tidy either way.

Using !r to surface exactly what Python received, useful when output looks wrong:

python
name  = input("Enter your name: ")
score = float(input("Enter your score (0.0 to 1.0): "))

print(f"Name:   {name!r}")
print(f"Score:  {score!r}")
print()
print(f"Result: {name}: {score:.1%}")

{name} and {name!r} display identically when input is clean. The difference appears when there are trailing spaces or other invisible characters. Getting into the habit of !r during debugging makes unexpected values visible immediately.

Practice output and input in PythonWork through hands-on exercises on print, f-strings, and user input in the Scrimba course.Start the course →