Version-Neutral Printing

Finally, if you cannot restrict your work to Python 3.0 but still want your prints to be compatible with 3.0, you have some options. For one, you can code 2.6 print statements and let 3.0’s 2to3 conversion script translate them to 3.0 function calls automatically. See the Python 3.0 documentation for more details about this script; it attempts to translate 2.X code to run under 3.0.

Alternatively, you can code 3.0 print function calls in your 2.6 code, by enabling the function call variant with a statement like the following:

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

from __future__ import print_function

This statement changes 2.6 to support 3.0’s print functions exactly. This way, you can use 3.0 print features and won’t have to change your prints if you later migrate to 3.0.

Also keep in mind that simple prints, like those in the first row of Table 11-5, work in either version of Python—because any expression may be enclosed in parentheses, we can always pretend to be calling a 3.0 print function in 2.6 by adding outer parentheses. The only downside to this is that it makes a tuple out of your printed objects if there are more than one—they will print with extra enclosing parentheses. In 3.0, for example, any number of objects may be listed in the call’s parentheses:

C:\misc> c:\python30\python
>>> print('spam')                       # 3.0 print function call syntax
spam
>>> print('spam', 'ham', 'eggs')        # These are mutiple argments
spam ham eggs

The first of these works the same in 2.6, but the second generates a tuple in the output:

C:\misc> c:\python26\python
>>> print('spam')                       # 2.6 print statement, enclosing parens
spam
>>> print('spam', 'ham', 'eggs')        # This is really a tuple object!
('spam', 'ham', 'eggs')

To be truly portable, you can format the print string as a single object, using the string formatting expression or method call, or other string tools that we studied in Chapter 7:

>>> print('%s %s %s' % ('spam', 'ham', 'eggs'))
spam ham eggs
>>> print('{0} {1} {2}'.format('spam', 'ham', 'eggs'))
spam ham eggs

Of course, if you can use 3.0 exclusively you can forget such mappings entirely, but many Python programmers will at least encounter, if not write, 2.X code and systems for some time to come.


Note

I use Python 3.0 print function calls throughout this book. I’ll usually warn you that the results may have extra enclosing parentheses in 2.6 because multiple items are a tuple, but I sometimes don’t, so please consider this note a blanket warning—if you see extra parentheses in your printed text in 2.6, either drop the parentheses in your print statements, recode your prints using the version-neutral scheme outlined here, or learn to love superfluous text.



Why You Will Care: print and stdout

The equivalence between the print operation and writing to sys.stdout is important. It makes it possible to reassign sys.stdout to any user-defined object that provides the same write method as files. Because the print statement just sends text to the sys.stdout.write method, you can capture printed text in your programs by assigning sys.stdout to an object whose write method processes the text in arbitrary ways.

For instance, you can send printed text to a GUI window, or tee it off to multiple destinations, by defining an object with a write method that does the required routing. You’ll see an example of this trick when we study classes in Part VI of this book, but abstractly, it looks like this:

class FileFaker:
    def write(self, string):
        # Do something with printed text in string

import sys
sys.stdout = FileFaker()
print(someObjects)              # Sends to class write method

This works because print is what we will call in the next part of this book a polymorphic operation—it doesn’t care what sys.stdout is, only that it has a method (i.e., interface) called write. This redirection to objects is made even simpler with the file keyword argument in 3.0 and the >> extended form of print in 2.6, because we don’t need to reset sys.stdout explicitly—normal prints will still be routed to the stdout stream:

myobj = FileFaker()             # 3.0: Redirect to object for one print
print(someObjects, file=myobj)  # Does not reset sys.stdout

myobj = FileFaker()             # 2.6: same effect
print >> myobj, someObjects     # Does not reset sys.stdout

Python’s built-in input function reads from the sys.stdin file, so you can intercept read requests in a similar way, using classes that implement file-like read methods instead. See the input and while loop example in Chapter 10 for more background on this.

Notice that because printed text goes to the stdout stream, it’s the way to print HTML in CGI scripts used on the Web. It also enables you to redirect Python script input and output at the operating system’s shell command line, as usual:

python script.py < inputfile > outputfile
python script.py | filterProgram

Python’s print operation redirection tools are essentially pure-Python alternatives to these shell syntax forms.


 


[29] Technically, printing uses the equivalent of str in the internal implementation of Python, but the effect is the same. Besides this to-string conversion role, str is also the name of the string data type and can be used to decode Unicode strings from raw bytes with an extra encoding argument, as we’ll learn in Chapter 36; this latter role is an advanced usage that we can safely ignore here.

[30] In both 2.6 and 3.0 you may also be able to use the __stdout__ attribute in the sys module, which refers to the original value sys.stdout had at program startup time. You still need to restore sys.stdout to sys.__stdout__ to go back to this original stream value, though. See the sys module documentation for more details.