154 lines
4.9 KiB
Plaintext
154 lines
4.9 KiB
Plaintext
PEP: 214
|
||
Title: Extended Print Statement
|
||
Version: $Revision$
|
||
Owner: bwarsaw@beopen.com (Barry A. Warsaw)
|
||
Python-Version: 2.0
|
||
Status: Draft
|
||
|
||
|
||
|
||
Introduction
|
||
|
||
This PEP describes a syntax to extend the standard `print'
|
||
statement so that it can be used to print to any file-like object,
|
||
instead of the default sys.stdout. This PEP tracks the status and
|
||
ownership of this feature. It contains a description of the
|
||
feature and outlines changes necessary to support the feature.
|
||
This PEP summarizes discussions held in mailing list forums, and
|
||
provides URLs for further information, where appropriate. The CVS
|
||
revision history of this file contains the definitive historical
|
||
record.
|
||
|
||
|
||
|
||
Justification
|
||
|
||
`print' is a Python keyword and introduces the print statement as
|
||
described in section 6.6 of the language reference manual[1].
|
||
The print statement has a number of features:
|
||
|
||
- it auto-converts the items to strings
|
||
- it inserts spaces between items automatically
|
||
- it appends a newline unless the statement ends in a comma
|
||
|
||
The formatting that the print statement performs is limited; for
|
||
more control over the output, a combination of sys.stdout.write(),
|
||
and string interpolation can be used.
|
||
|
||
The print statement by definition outputs to sys.stdout. More
|
||
specifically, sys.stdout must be a file-like object with a write()
|
||
method, but it can be rebound to redirect output to files other
|
||
than specifically standard output. A typical idiom is
|
||
|
||
oldstdout = sys.stdout
|
||
sys.stdout = mylogfile
|
||
try:
|
||
print 'this message goes to my log file'
|
||
finally:
|
||
sys.stdout = oldstdout
|
||
|
||
The problem with this approach is that the binding is global, and
|
||
so affects every statement inside the try: clause. For example,
|
||
if we added a call to a function that actually did want to print
|
||
to stdout, this output too would get redirected to the logfile.
|
||
|
||
|
||
|
||
Proposal
|
||
|
||
This proposal introduces a syntax change to the print statement,
|
||
which allows the programmer to optionally specify the output file
|
||
target. An example usage is as follows:
|
||
|
||
print >> mylogfile, 'this message goes to my log file'
|
||
|
||
Formally, the syntax of the extended print statement is
|
||
|
||
print_stmt: "print" [">>" expr ","] [ expr ("," expr)* [","] ]
|
||
|
||
Where the the expression just after >> must yield an object with a
|
||
write() method (i.e. a file-like object). Thus these two
|
||
statements are equivalent:
|
||
|
||
print 'hello world'
|
||
print >> sys.stdout, 'hello world'
|
||
|
||
|
||
|
||
Reference Implementation
|
||
|
||
A reference implementation, in the form of a patch against the
|
||
Python 2.0 source tree, is available on SourceForge's patch
|
||
manager[2]. The approach this patch takes is to introduce two new
|
||
opcodes, one which temporarily rebinds sys.stdout to the specified
|
||
file object, performs the print as normal, and then bind
|
||
sys.stdout back to sys.__stdout__ (which is the real physical
|
||
standard out and should not be changed). In some ways this is
|
||
equivalent to the try/finally idiom above, except that the
|
||
rebinding of sys.stdout is in effect only for the duration of the
|
||
print statement itself.
|
||
|
||
An alternative approach is possible, where only one new opcode is
|
||
added. This opcode would be exactly like the existing PRINT_ITEM
|
||
opcode except that it would find the target file object at the top
|
||
of the stack, and use this file instead of digging it out of
|
||
sys.stdout.
|
||
|
||
|
||
|
||
Alternative Approaches
|
||
|
||
An alternative to this syntax change has been proposed (originally
|
||
by Moshe Zadka) which requires no syntax changes to Python. A
|
||
writeln() function could be provided (possibly as a builtin), that
|
||
would act much like extended print, with a few additional
|
||
features.
|
||
|
||
def writeln(*args, **kws):
|
||
import sys
|
||
file = sys.stdout
|
||
sep = ' '
|
||
end = '\n'
|
||
if kws.has_key('file'):
|
||
file = kws['file']
|
||
del kws['file']
|
||
if kws.has_key('nl'):
|
||
if not kws['nl']:
|
||
end = ' '
|
||
del kws['nl']
|
||
if kws.has_key('sep'):
|
||
sep = kws['sep']
|
||
del kws['sep']
|
||
if kws:
|
||
raise TypeError('unexpected keywords')
|
||
file.write(sep.join(map(str, args)) + end)
|
||
|
||
writeln() takes a three optional keyword arguments. In the
|
||
context of this proposal, the relevant argument is `file' which
|
||
can be set to a file-like object with a write() method. Thus
|
||
|
||
print >> mylogfile, 'this goes to my log file'
|
||
|
||
would be written as
|
||
|
||
writeln('this goes to my log file', file=mylogfile)
|
||
|
||
writeln() has the additional functionality that the keyword
|
||
argument `nl' is a flag specifying whether to append a newline or
|
||
not, and an argument `sep' which specifies the separator to output
|
||
in between each item.
|
||
|
||
|
||
|
||
References
|
||
|
||
[1] http://www.python.org/doc/current/ref/print.html
|
||
[2] http://sourceforge.net/patch/download.php?id=100970
|
||
|
||
|
||
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
End:
|