Input and output
Every utility reads from somewhere and writes to somewhere. Keeping stdout and stderr separate is what makes your tool composable.
- Print data output to stdout with print()
- Write diagnostic messages to stderr with sys.stderr.write()
- Read all of stdin with sys.stdin.read()
- Explain why separating stdout and stderr matters in a pipeline
Every program has three standard streams available from the moment it starts: stdin (standard input), stdout (standard output), and stderr (standard error). A good utility uses all three correctly and keeps them strictly separate.
stdout is for data, stderr is for humans
This is the rule that most beginners get wrong. When your utility produces output, ask yourself: is this the result of the computation, or is it a message about the computation?
- stdout is the data channel. Whatever you write here is what the next program in the pipeline will read. Keep it clean: no progress messages, no "Processing…", no banners. Just the data.
- stderr is the diagnostic channel. Error messages, warnings, progress indicators, debug logs — all of this goes to stderr. Users see it in the terminal, but pipelines ignore it.
In Python: print() writes to stdout by default. To write to stderr, use
sys.stderr.write() (and don't forget the newline \n — write() won't add one
automatically).
Reading from stdin
sys.stdin.read() reads everything that's piped in and returns it as a string.
sys.stdin.readlines() returns a list of lines. Both block until the input stream
closes (which happens automatically when the upstream program finishes, or when
you press Ctrl-D in a terminal).
For many utilities, the cleanest pattern is: read all of stdin, process it, write to stdout, exit. No intermediate state, no side effects.
Try it
This block simulates all three streams. Edit it to see how each stream behaves:
Run it. Notice that both outputs appear in the terminal here — in a real shell,
2>/dev/null would suppress the stderr message, leaving only the clean data on
stdout.
When you redirect output in a shell — python mytool.py > results.txt — only
stdout goes into the file. stderr still prints to the terminal. That is exactly
what you want: clean data in the file, diagnostic messages visible to the
operator.
Why the separation matters
Imagine a utility that prints a progress message — "Reading 1000 lines…" — to
stdout. Now pipe it into wc -l. The count will be off by one (or more). The
downstream tool cannot distinguish your progress message from your data, because
you put both in the same stream.
Keeping stdout clean is not a style preference. It is what makes your tool trustworthy in a pipeline.
Where to go next
Next: composability — how programs chain together through pipes, and the properties that make a program composable.