Chapter 04 of 24 | Python

Input and output

Programs become useful when they can accept data and communicate results. input() reads a line from the user and always returns a string. Convert that string only after deciding what format is valid.

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

Validate before using input

raw_age = input("Age: ")
try:
    age = int(raw_age)
except ValueError:
    print("Please enter a whole number.")
else:
    if age < 0:
        print("Age cannot be negative.")
    else:
        print(f"Next year you will be {age + 1}.")

Conversion and validation are separate: int checks whether text can be interpreted as an integer, while the domain rule checks whether that integer is acceptable. Catch the specific expected exception, not every possible exception. A retry loop can improve the experience, but it should have a clear exit path.

Output and formatting

print writes text to standard output. Its sep parameter controls separators between values and end controls the ending. F-strings are a readable way to present computed values. Formatting is presentation, however: a formatted number does not change the underlying numeric value.

amount = 12.5
print(f"Total: ${amount:.2f}")
print("one", "two", "three", sep=", ")

Standard output versus errors

import sys

print("Normal result")
print("Could not read the file", file=sys.stderr)

Standard output is for ordinary results; standard error is for diagnostics. A command-line user can redirect them independently, so mixing them can break scripts that expect machine-readable output. Keep prompts and status messages out of a data stream when the program is intended to be piped into another program.

Beginner-to-master progression

Exercises

  1. Ask for two numbers, handle invalid input, and display their sum.
  2. Format a percentage and a currency amount with a deliberate number of decimal places.
  3. Write a command-line script whose normal output is parseable while diagnostics go to standard error.

Parsing whole records

Interactive prompts are only one kind of input. A command may receive redirected data from a file or another process, so a robust program should not assume a person is typing. Read a complete line, strip only the characters allowed by the input grammar, and report a line number or field name when validation fails.

def parse_measurement(text):
    parts = text.split()
    if len(parts) != 2:
        raise ValueError("expected: NUMBER UNIT")
    value = float(parts[0])
    unit = parts[1].lower()
    if unit not in {"m", "km"}:
        raise ValueError(f"unsupported unit: {unit}")
    return value, unit

This function validates shape, converts the numeric component, and restricts units. In production, also define rules for NaN, infinity, signs, whitespace, and allowable magnitude. Validation should happen at the boundary, before untrusted values enter the program's core model.

Buffering, pipelines, and failure contracts

Standard output may be buffered, especially when redirected. Do not rely on every printed line immediately reaching a terminal or file. Use explicit flushing for interactive prompts that need it, and let normal buffering improve throughput for bulk output. If a program is part of a pipeline, a nonzero exit status should communicate failure to the next tool.

Choose whether a batch processor stops at the first invalid record or reports all failures. The choice affects its contract: streaming a million records with immediate output can leave partial output on failure. When atomic output matters, write to a temporary destination and publish it only after the entire operation succeeds.

Mastery checkpoint

  1. Specify a line-oriented input grammar and implement a parser that rejects trailing fields.
  2. Process redirected input without prompts and use exit codes and standard error consistently.
  3. Design a batch-output strategy that avoids publishing a partial result as if it were complete.
0% read