Python input and output: input(), print(), sys.argv and formatting
Advertisement
A program is only useful if it can take something in and give something back. In Python, the two basic doors are the input() function, which reads what the user types, and print(), which shows results. Beyond these, programs also get information from the command line and from files. This post covers keyboard input, converting what you read, reading several values at once, command-line arguments, and the many things print() can do. The outputs shown were produced by running the code on Python 3.9, with input supplied through a pipe so that the runs could be repeated.
Reading input with input()
input(prompt) shows the prompt, waits for the user to type a line and press Enter, and returns the line as a string, without the newline.
name = input("Your name: ")
print("Hello,", name)
Running it and typing Asha gives:
Your name: Asha
Hello, Asha
The important fact is the type. Even when the user types digits, input() returns text:
x = input("Number: ") # the user types 21
print(x, type(x), x + x) # 21 <class 'str'> 2121
x + x joined two strings instead of adding two numbers. To compute with the value, convert it.
Converting the input
| Function | Converts to | Fails with ValueError for |
|---|---|---|
int(s) |
integer | "3.5", "abc", "" |
float(s) |
float | "abc", "" |
bool(s) |
True for any non-empty string | never (so bool("False") is True) |
str(x) |
text | never |
age = int("21")
price = float("19.99")
print(age + 1, price * 2, int(" 7 ")) # 22 39.98 7
print(bool("False"), bool("")) # True False
try:
int("3.5")
except ValueError as e:
print(e) # invalid literal for int() with base 10: '3.5'
int() and float() ignore spaces around the number. To turn "3.5" into an integer, go through a float: int(float("3.5")) is 3. For a yes/no question, compare text instead of using bool: answer.strip().lower() in ("y", "yes").
Asking again until the input is valid
Users type mistakes, so wrap the conversion in a loop with try/except:
def ask_int(prompt):
while True:
text = input(prompt)
try:
return int(text)
except ValueError:
print("Please type a whole number.")
n = ask_int("How many? ")
print("You asked for", n)
With the three lines abc, 4.5, 12 supplied, the output was:
How many? Please type a whole number.
How many? Please type a whole number.
How many? You asked for 12
(The prompts run together here because the answers came from a pipe instead of a keyboard; on a terminal each prompt appears after the previous answer.) This pattern, ask, convert, retry, is worth memorising.
Reading several values
Often you want several numbers from one line. Read the line, split() it and convert each piece:
line = "10 20 30" # imagine: line = input()
nums = [int(p) for p in line.split()]
print(nums, sum(nums)) # [10, 20, 30] 60
a, b = map(int, "7 5".split()) # unpack straight into names
print(a + b, a * b) # 12 35
split() with no argument splits on any amount of whitespace. For comma-separated input use split(",") and strip() each part, since the pieces may carry spaces. If you want to read many lines until the user stops, loop over sys.stdin:
import sys
total = 0
for line in sys.stdin:
total += int(line)
print(total)
Run it with printf '1\n2\n3\n' | python3 sum.py and it prints 6. The loop ends at the end of the input (Ctrl+D on macOS and Linux, Ctrl+Z then Enter on Windows). This is also how programs read piped data and how online judges feed test cases.
A word on eval()
Some old tutorials suggest eval(input()) to read a number or a list. eval runs whatever the user types as Python code, so a user could type something harmful. Never use it on input you do not control. For literal values such as a list, ast.literal_eval is the safe replacement:
import ast
print(ast.literal_eval("[1, 2, 3]"), ast.literal_eval("{'a': 1}")) # [1, 2, 3] {'a': 1}
Command-line arguments
Instead of asking questions, many programs receive their values on the command line: python3 tool.py report.csv 5. Python provides them in sys.argv, a list of strings. The first item is the script's name.
# args.py
import sys
print(sys.argv)
print(len(sys.argv) - 1, "arguments")
if len(sys.argv) > 1:
print("first:", sys.argv[1], "doubled:", int(sys.argv[2]) * 2 if len(sys.argv) > 2 else "n/a")
Running python3 args.py hello 21 printed:
['args.py', 'hello', '21']
2 arguments
first: hello doubled: 42
Every item is a string, so convert numbers yourself. An argument with spaces needs quotes in the shell (python3 args.py "hello world"), otherwise it becomes two arguments. If a required argument is missing, sys.argv[1] raises IndexError; check len(sys.argv) first.
argparse for real tools
When a program has options, help text or several arguments, use the standard argparse module. It checks the arguments, converts types and writes the --help page for you:
# greet.py
import argparse
parser = argparse.ArgumentParser(description="Greet someone")
parser.add_argument("name")
parser.add_argument("--times", type=int, default=1)
args = parser.parse_args()
for _ in range(args.times):
print("Hello,", args.name)
python3 greet.py Asha --times 2 printed Hello, Asha twice. Calling it without a name prints error: the following arguments are required: name, and --times abc is rejected with argument --times: invalid int value: 'abc'. That error handling would take many lines to write by hand.
Output with print()
print() accepts any number of values, converts each to text and writes them separated by a space, followed by a newline.
print("a", 1, 2.5, [3], None) # a 1 2.5 [3] None
print() # an empty line
Four keyword arguments change its behaviour:
print("a", "b", "c", sep="-") # a-b-c
print("loading", end="...") # no newline at the end
print("done") # loading...done
print("x", "y", sep="") # xy
sep is put between values (default one space), and end is put after the last one (default a newline). Setting end="" keeps the cursor on the same line, which is how progress messages and for loops that print on one line are made.
file= sends the output somewhere else, such as the error stream or an open file:
import sys
print("something went wrong", file=sys.stderr)
with open("out.txt", "w") as f:
print("saved line", file=f)
print(open("out.txt").read(), end="") # saved line
Use sys.stderr for error messages so they do not mix with the program's normal output when someone redirects it. The fourth argument, flush=True, forces the text out immediately, which matters when you print slow progress messages.
Formatting output
You will usually want numbers in a tidy layout. The modern tool is the f-string:
name, price, qty = "Tea", 49.5, 3
print(f"{name}: {qty} x {price} = {qty * price}") # Tea: 3 x 49.5 = 148.5
print(f"{name:<8}|{price:>8.2f}|{qty:03d}") # Tea | 49.50|003
print(f"{1234567.891:,.2f} {0.256:.1%} {255:#x}") # 1,234,567.89 25.6% 0xff
Between the braces you can put any expression, and after a colon a format: < and > align left and right, .2f means two decimals, 03d pads an integer with zeros, , adds thousands separators. The older ways still work and appear in existing code:
print("%s costs %.2f" % ("Tea", 49.5)) # Tea costs 49.50
print("{} costs {:.2f}".format("Tea", 49.5)) # Tea costs 49.50
The strings post has a fuller table of formats. A small receipt shows how alignment helps:
items = [("Tea", 2, 49.5), ("Biscuits", 1, 30.0)]
for item, qty, price in items:
print(f"{item:<10}{qty:>3}{price:>9.2f}")
print("-" * 22)
print(f"{'Total':<10}{'':>3}{sum(q * p for _, q, p in items):>9.2f}")
Tea 2 49.50
Biscuits 1 30.00
----------------------
Total 129.00
Reading from and writing to files
Console input and output are only two streams. Files work with open(), read() and write(); the file handling post covers them, and print(..., file=f) shown above is a quick way to write text lines.
Common mistakes
- Forgetting that
input()returns a string and adding two inputs as text. - Using
bool(input())to read True/False; any non-empty text isTrue. - Using
eval(input())on untrusted input. - Reading
sys.argv[1]without checking that it exists, and forgetting that arguments are strings. - Printing error messages to standard output instead of
sys.stderr. - Using
end=""and then forgetting the final newline, so the shell prompt appears on the same line. - Concatenating numbers and text with
+("Total: " + 5raisesTypeError); use an f-string instead.
Practice
Write a program that asks for three numbers on one line, converts them, and prints their sum and average to two decimals. Make it retry until the input is valid. Then change it so the numbers come from sys.argv, and finally rebuild it with argparse so that --round 3 controls the number of decimals.
Continue
Next learn how to organise code into functions, and control the flow of your program with conditions and loops. The operators post explains the arithmetic you use on input, and the Python video course walks through all of this with demonstrations.