Explain Codes LogoExplain Codes Logo

How do I read from stdin?

python
input
stdin
io
Alex KataevbyAlex Kataev·Sep 14, 2024
TLDR

To capture input via input() for a single line:

user_input = input() print(user_input)

To read multiple lines or piped input, sys.stdin comes in handy:

import sys content = sys.stdin.read() print(content)

By reading until an End Of File (EOF). For line-by-line processing, iterate over sys.stdin:

for line in sys.stdin: print(line, end='')

Hit Ctrl+D (Unix) or Ctrl+Z (Windows) at the terminal to signal EOF. Dealing with a script which demands both a data stream and filenames? Use the fileinput module:

import fileinput for line in fileinput.input(): process(line)

A step beyond single lines: interactive prompts and multi-line input

The input() function supports interactivity through inline prompts:

name = input("Enter your name: ") # Kindly asking for the user's name print(f"Hello {name}!") # Our program is polite, it always greets back!

To fetch multi-line input, use a sentinel-controlled loop where a unique word or character signals the end of the input:

print("Enter your content (type 'done' to stop):") # Friendly instruction lines = [] while True: # It's a conversation until it's 'done' line = input() if line == "done": break lines.append(line) print("\n".join(lines))

The devil lies in the details: Stripping newlines, handling EOF, and command-line arguments

When processing lines, make it clean by stripping newlines:

for line in sys.stdin: clean_line = line.rstrip() print(clean_line)

EOF, being required to terminate scripts, can be a complication in non-interactive inputs, e.g. pipes or files. A loop over sys.stdin can help your script respond dynamically to incoming lines without requiring explicit EOF.

Along with sys.stdin, sys.argv offers flexibility when input could come from a file or stdin:

import sys import fileinput # Reading from files if command-line arguments are present, otherwise from stdin for line in fileinput.input(files=(sys.argv[1:] if sys.argv[1:] else ('-',))): print(line, end='')

Sidestepping common bugs and securing data: Pitfalls and edge cases

Recall the crucial difference between Python 2.x's input(), which evaluates input as Python code. For raw string input, always use input() in Python 3 and raw_input() in Python 2.

Validating and sanitizing inputs prevent mishaps with malicious data:

user_input = input() if not user_input.isalpha(): print("Input is not alphabetic!") # Someone's trying to fool us! else: print("Input is safe to use!") # All clear, we're safe now!

Windows users and Unix aficionados can whip up pipes with commands type and cat respectively:

cat file.txt | python myscript.py # Unix type file.txt | python myscript.py # Windows

The book "Learning Python" by Mark Lutz offers comprehensive guidance on efficient I/O handling.

Breaking down the input processing pipeline

fileinput truly shines when piped input and multiple-file handling come up:

# Echoes piped input or contents of multiple files for line in fileinput.input(): print(line) # Whoa, I can read from stdin and files?

For powerful chained processing, call on Unix tools like cat, grep, or awk.

For efficient management of I/O operations, design function abstractions:

def process_input(source=sys.stdin): for line in source: # Fairy dust to make our lines clean! yield line.rstrip() # Usage with stdin for clean_line in process_input(): process(clean_line) # Processing stdin, one clean line at a time! # Usage with file contents with open('my-input-file.txt', 'r') as input_file: for clean_line in process_input(input_file): # Even file content can't escape our cleaning crew! process(clean_line)

Intelligent handling of interactive and non-interactive modes can often be achieved through elegant defaults and checks.