Thesys
module
is also the place where the standard input, output, and
error streams of your Python programs live; these turn out to be another
common way for programs to communicate:
>>>import sys
>>>for f in (sys.stdin, sys.stdout, sys.stderr): print(f)
...
<_io.TextIOWrapper name='' encoding='cp437'>
<_io.TextIOWrapper name='' encoding='cp437'>
<_io.TextIOWrapper name='' encoding='cp437'>
The standard streams are simply preopened Python file objects that
are automatically connected to your program’s standard streams when Python
starts up. By default, all of them are tied to the console window where
Python (or a Python program) was started. Because theprint
andinput
built-in functions are really nothing more
than user-friendly interfaces to the standard output and input streams,
they are similar to usingstdout
andstdin
insys
directly:
>>>print('hello stdout world')
hello stdout world
>>>sys.stdout.write('hello stdout world' + '\n')
hello stdout world
19
>>>input('hello stdin world>')
hello stdin world>spam
'spam'
>>>print('hello stdin world>'); sys.stdin.readline()[:-1]
hello stdin world>eggs
'eggs'
Standard Streams on Windows
Windows users:
if you click a
.py
Python program’s
filename in a Windows file explorer to start it (or launch it withos.system
), a DOS console window
automatically pops up to serve as the program’s standard stream. If your
program makes windows of its own, you can avoid this console pop-up
window by naming your program’s source-code file with a
.pyw
extension, not with a
.py
extension. The
.pyw
extension simply means a
.py
source file without a DOS pop up on Windows (it
uses Windows registry settings to run a custom version of Python). A
.pyw
file may also be imported as usual.
Also note that because printed output goes to this DOS pop up when
a program is clicked, scripts that simply print text and exit will
generate an odd “flash”—the DOS console box pops up, output is printed
into it, and the pop up goes away immediately (not the most
user-friendly of features!). To keep the DOS pop-up box around so that
you can read printed output, simply add aninput()
call at the bottom of your script to
pause for an Enter key press before exiting.
Technically,
standard output (andprint
) text appears in the console window
where a program was started, standard input (andinput
) text comes from the keyboard, and
standard error text is used to print Python error messages to the
console window. At least that’s the default. It’s also possible to
redirect
these streams both to files and to other
programs at the system shell, as well as to arbitrary objects within a
Python script. On most systems, such redirections make it easy to reuse
and combine general-purpose command-line utilities.
Redirection is useful for things like canned (precoded) test
inputs: we can apply a single test script to any set of inputs by simply
redirecting the standard input stream to a different file each time the
script is run. Similarly, redirecting the standard output stream lets us
save and later analyze a program’s output; for example, testing systems
might compare the saved standard output of a script with a file of
expected output to detect failures.
Although it’s a powerful paradigm, redirection turns out to be
straightforward to use. For instance, consider the simple
read-evaluate-print loop program in
Example 3-5
.
Example 3-5. PP4E\System\Streams\teststreams.py
"read numbers till eof and show squares"
def interact():
print('Hello stream world') # print sends to sys.stdout
while True:
try:
reply = input('Enter a number>') # input reads sys.stdin
except EOFError:
break # raises an except on eof
else: # input given as a string
num = int(reply)
print("%d squared is %d" % (num, num ** 2))
print('Bye')
if __name__ == '__main__':
interact() # when run, not imported
As usual, theinteract
function here
is automatically executed when this file is run, not when it is
imported. By default, running this file from a system command line makes
that standard stream appear where you typed the Python command. The
script simply reads numbers until it reaches
end-of-file in the standard input stream (on Windows,
end-of-file is usually the two-key combination
Ctrl-Z; on Unix, type Ctrl-D instead
[
8
]
):
C:\...\PP4E\System\Streams>python teststreams.py
Hello stream world
Enter a number>12
12 squared is 144
Enter a number>10
10 squared is 100
Enter a number>^Z
Bye
But on both
Windows and Unix-like platforms, we can redirect the
standard input stream to come from a file with the<
filename
shell
syntax. Here is a command session in a DOS console box on Windows that
forces the script to read its input from a text file,
input.txt
. It’s the same on Linux, but replace the
DOStype
command with a Unixcat
command:
C:\...\PP4E\System\Streams>type input.txt
8
6
C:\...\PP4E\System\Streams>python teststreams.py < input.txt
Hello stream world
Enter a number>8 squared is 64
Enter a number>6 squared is 36
Enter a number>Bye
Here, the
input.txt
file automates the input
we would normally type interactively—the script reads from this file
rather than from the keyboard. Standard output can be similarly
redirected to go to a file with the>
filename
shell
syntax. In fact, we can combine input and output redirection in a single
command:
C:\...\PP4E\System\Streams>python teststreams.py < input.txt > output.txt
C:\...\PP4E\System\Streams>type output.txt
Hello stream world
Enter a number>8 squared is 64
Enter a number>6 squared is 36
Enter a number>Bye
This time, the Python script’s input and output are both mapped to
text files, not to the interactive console session.
On Windows
and Unix-like platforms, it’s also possible to send the
standard output of one program to the standard input of another using
the|
shell character between two
commands. This is usually called a “pipe” operation because the shell
creates a pipeline that connects the output and input of two commands.
Let’s send the output of the Python script to the standardmore
command-line program’s input to see how
this works:
C:\...\PP4E\System\Streams>python teststreams.py < input.txt | more
Hello stream world
Enter a number>8 squared is 64
Enter a number>6 squared is 36
Enter a number>Bye
Here,teststreams
’s standard
input comes from a file again, but its output (written byprint
calls) is sent to another program, not
to a file or window. The receiving program ismore
, a standard command-line paging program
available on Windows and Unix-like platforms. Because Python ties
scripts into the standard stream model, though, Python scripts can be
used on both ends. One Python script’s output can always be piped into
another Python script’s input:
C:\...\PP4E\System\Streams>type writer.py
print("Help! Help! I'm being repressed!")
print(42)
C:\...\PP4E\System\Streams>type reader.py
print('Got this: "%s"' % input())
import sys
data = sys.stdin.readline()[:-1]
print('The meaning of life is', data, int(data) * 2)
C:\...\PP4E\System\Streams>python writer.py
Help! Help! I'm being repressed!
42
C:\...\PP4E\System\Streams>python writer.py | python reader.py
Got this: "Help! Help! I'm being repressed!"
The meaning of life is 42 84
This time, two Python programs are connected. Scriptreader
gets input from scriptwriter
; both scripts simply read and write,
oblivious to stream mechanics. In practice, such chaining of programs
is a simple form of cross-program communications. It makes it easy to
reuse
utilities written to communicate viastdin
andstdout
in ways we never anticipated. For
instance, a Python program that sortsstdin
text could be applied to any data
source we like, including the output of other scripts. Consider the
Python command-line utility scripts in Examples
3-6
and
3-7
which sort and sum lines in the
standard input stream.
Example 3-6. PP4E\System\Streams\sorter.py
import sys # or sorted(sys.stdin)
lines = sys.stdin.readlines() # sort stdin input lines,
lines.sort() # send result to stdout
for line in lines: print(line, end='') # for further processing
Example 3-7. PP4E\System\Streams\adder.py
import sys
sum = 0
while True:
try:
line = input() # or call sys.stdin.readlines()
except EOFError: # or for line in sys.stdin:
break # input strips \n at end
else:
sum += int(line) # was sting.atoi() in 2nd ed
print(sum)
We can apply such general-purpose tools in a variety of ways at
the shell command line to sort and sum arbitrary files and program
outputs (Windows note: on my prior XP machine and Python 2.X, I had to
type “python file.py” here, not just “file.py,” or else the input
redirection failed; with Python 3.X on Windows 7 today, either form
works):
C:\...\PP4E\System\Streams>type data.txt
123
000
999
042
C:\...\PP4E\System\Streams>python sorter.py < data.txt
sort a file
000
042
123
999
C:\...\PP4E\System\Streams>python adder.py < data.txt
sum file
1164
C:\...\PP4E\System\Streams>type data.txt | python adder.py
sum type output
1164
C:\...\PP4E\System\Streams>type writer2.py
for data in (123, 0, 999, 42):
print('%03d' % data)
C:\...\PP4E\System\Streams>python writer2.py | python sorter.py
sort py output
000
042
123
999
C:\...\PP4E\System\Streams>writer2.py | sorter.py
shorter form
...same output as prior command on Windows...
C:\...\PP4E\System\Streams>python writer2.py | python sorter.py | python adder.py
1164
The last command here connects three Python scripts by standard
streams—the output of each prior script is fed to the input of the
next via pipeline shell syntax.
A few coding pointers here: if you look closely, you’ll notice
that
sorter.py
reads all ofstdin
at once with thereadlines
method, but
adder.py
reads one line at a time. If the
input source is another program, some platforms run programs connected
by pipes in
parallel
. On such systems, reading
line by line works better if the data streams being passed are large,
because readers don’t have to wait until writers are completely
finished to get busy processing data. Becauseinput
just readsstdin
, the line-by-line scheme used by
adder.py
can always be coded with
manualsys.stdin
reads too:
C:\...\PP4E\System\Streams>type adder2.py
import sys
sum = 0
while True:
line = sys.stdin.readline()
if not line: break
sum += int(line)
print(sum)
This version utilizes the fact thatint
allows the digits to be surrounded by
whitespace (readline
returns a line
including its\n
, but we don’t have
to use[:-1]
orrstrip()
to remove it forint
). In fact, we can use Python’s more
recent file iterators to achieve the same effect—thefor
loop, for example, automatically grabs
one line each time through when we iterate over a file object directly
(more on file iterators in the next chapter):
C:\...\PP4E\System\Streams>type adder3.py
import sys
sum = 0
for line in sys.stdin: sum += int(line)
print(sum)
Changingsorter
to read line
by line this way may not be a big performance boost, though, because
the listsort
method requires that
the list already be complete. As we’ll see in
Chapter 18
, manually coded sort algorithms are
generally prone to be much slower than the Python list sorting
method.
Interestingly, these two scripts can also be coded in a much
more compact fashion in Python 2.4 and later by using the
newsorted
built-in
function, generator expressions, and file iterators. The following
work the same way as the originals, with noticeably less source-file
real estate:
C:\...\PP4E\System\Streams>type sorterSmall.py
import sys
for line in sorted(sys.stdin): print(line, end='')
C:\...\PP4E\System\Streams>type adderSmall.py
import sys
print(sum(int(line) for line in sys.stdin))
In its argument tosum
, the
latter of these employs a generator expression, which is much like a
list comprehension, but results are returned one at a time, not in a
physical list. The net effect is space optimization. For more details,
see a core language resource, such as the
book
Learning
Python
.