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:
|