Fast input and output
- Module
- M3.10
- Lesson
- 1 of 1
- Reading time
- 4 min
In this lesson
- Use sys.stdin.read() to read large amounts of input quickly.
- Parse input using split() for faster token processing.
- Build output as a list and print it all at once.
- Apply the house skeleton pattern for high-throughput I/O.
On larger problems, plain input() becomes a bottleneck. Each call to input() reads one line. If you have thousands of lines, thousands of calls add up. Python has a faster way: read everything at once, parse it, and output everything at once.
The house skeleton pattern
The house skeleton is a standard pattern for fast I/O in competitive programming:
import sys
def main() -> None: input_data = sys.stdin.read().split() if not input_data: return # Parse and process # Build output list # output_list = [...] # sys.stdout.write("\n".join(output_list))
if __name__ == "__main__": main()Instead of calling input() many times, sys.stdin.read() reads all input at once. The split() call breaks the entire input into tokens (whitespace-separated words and numbers). Then you parse from this list of strings.
For output, instead of calling print() many times, collect results in a list and print them all at once with sys.stdout.write().
Reading tokens
After calling sys.stdin.read().split(), you have a list of strings. Read from it using an index:
import sys
def main() -> None: tokens = sys.stdin.read().split() idx = 0 n = int(tokens[idx]) idx += 1 total = 0 for i in range(n): val = int(tokens[idx]) idx += 1 total += val sys.stdout.write(f"{total}\n")
if __name__ == "__main__": main()Increment idx after reading each token. This is fast because split() has already done the heavy parsing work.
When to use fast I/O
Plain input() and print() are fine for small inputs. Use the house skeleton when you have thousands of lines or when a time limit is tight. The difference between fast and slow I/O can mean the difference between accepted and rejected.
import sys
def main() -> None: tokens = sys.stdin.read().split() if not tokens: return
idx = 0 n = int(tokens[idx]) idx += 1
total = 0 for i in range(n): val = int(tokens[idx]) idx += 1 total += val
sys.stdout.write(str(total) + "\n")
if __name__ == "__main__": main()Input
5
10 20 30 40 50Output
150This program reads a count, then that many numbers, and sums them. The fast I/O pattern makes it quick even on large inputs.
Understanding I/O overhead
Each time you call input(), Python must acquire system resources, read a line from the input stream, and return a string. These operations have overhead beyond just reading the bytes. If you have 100,000 lines, that overhead is paid 100,000 times.
The house skeleton reads all input in one system call. The operating system transfers all data at once, then Python's split() tokenizes it in memory. The overhead is paid once, not repeatedly.
The same applies to output. Each print() call sends data to a buffer, then flushes it (or Python decides to flush it automatically). Multiple small writes are inefficient. Collecting output and writing once is faster.
For small inputs, the difference is negligible. For inputs with millions of numbers or strings, fast I/O can be the difference between accepted and time limit exceeded.
A CCC time limit is typically a few seconds, and a plain call to input() costs far more than a single array access once you add up its overhead. On a few dozen or a few hundred lines, that cost is too small to matter. On a hundred thousand lines, calling input() that many times can burn through a meaningful share of the time limit. Your program has not done any real work yet, and there is less room left for the algorithm itself.
Building output efficiently
Instead of printing each result as you compute it, collect results in a list:
import sys
def compute(i: int) -> int: return i * i
n = 5results = []for i in range(n): result = compute(i) results.append(str(result))
sys.stdout.write("\n".join(results) + "\n")The "\n".join() method concatenates all strings with newlines between them. This is faster than calling print() many times because it builds the full output string once, then writes it once.
Reading a grid with the token list
The token list works just as well when the input is a grid of numbers instead of a flat list of numbers. split() breaks the whole input into tokens on any whitespace, including the line breaks between rows. The grid's row structure disappears the moment you call it. A grid given as several rows of space-separated numbers becomes one long list of tokens with no memory of where each row ended. You have to track the row and column boundaries yourself, using the row and column counts the problem gives you.
import sys
def main() -> None: tokens = sys.stdin.read().split() idx = 0 rows = int(tokens[idx]) idx += 1 cols = int(tokens[idx]) idx += 1 grid = [] for r in range(rows): row = [] for c in range(cols): row.append(int(tokens[idx])) idx += 1 grid.append(row) sys.stdout.write(str(grid[0][0]) + "\n")
if __name__ == "__main__": main()The inner loop reads exactly cols tokens before the outer loop starts the next row, so idx always lands on the first token of the next row at the right moment. This is the same one-token-at-a-time reading from earlier, just organized into two loops instead of one. It scales to a grid of any size without ever calling input(). It also works whether the grid's rows are given one per input line or all run together, since split() treats both layouts the same way.
Common mistakes
One mistake is forgetting to handle edge cases like empty input. Always check if the token list is empty before accessing it.
Another mistake is mixing input() and sys.stdin.read(). They compete for input. Use one or the other, not both in the same program. If you use sys.stdin.read(), every token comes from that single read.
A third mistake is forgetting to import sys at the top of your program.
A fourth mistake is using sys.stdout.write() incorrectly. Remember that write() does not add a newline automatically, unlike print(). Build your output string with "\n".join(...) before writing, or concatenate "\n" explicitly.
A fifth trap is assuming the input is already parsed. After sys.stdin.read().split(), you have a list of strings. You still need to call int() or float() to convert tokens to numbers.
Fast I/O matters most on problems with large inputs. Reach for the house skeleton pattern when inputs are large or time limits are strict, and keep plain input() and print() for everything smaller.
Practice
Try these on the judges. Each link opens the problem on WMOJ or DMOJ.
- 2015 S2Jerseys (opens on DMOJ in a new tab) DMOJ
Process many assignments efficiently; the input size makes fast I/O worth using.
Why DMOJ: A large-input problem where the house skeleton pattern avoids slow input() calls.
- 2025 J4Sunny Days (opens on WMOJ in a new tab) WMOJ
Scan a large run of daily records fast enough to stay inside the time limit.