Pergunta

I searched around and couldn't find an answer to this either on this site or elsewhere (always a challenge searching for topics involving punctuation chars).

I was looking up the StringIO in the Python standard library (here) and one of the examples is this (excerpt):

import StringIO

output = StringIO.StringIO()
output.write('First line.\n')
print >>output, 'Second line.'  # <-- This is the line I'm asking about

How or why does the >> operator work here? As far as I can tell (and I'm no Python expert), this is the right shift operator. I thought perhaps StringIO overrides __rshift__ or something, but the source for StringIO does not betray any such thing.

I haven't poked around to see how the print built-in is implemented yet, but with initial searching I'm unable to figure out how this works. Anyone?

Foi útil?

Solução

This is really a few questions in one.


First, the "how" question:

The >> token is not actually an operator here; it's part of the syntax of the print statement, as documented here. The grammar is:

print_stmt ::=  "print" ([expression ("," expression)* [","]]
                | ">>" expression [("," expression)+ [","]])

… and the semantics are:

This form is sometimes referred to as “print chevron.” In this form, the first expression after the >> must evaluate to a “file-like” object, specifically an object that has a write() method as described above. With this extended form, the subsequent expressions are printed to this file object.


Second, the "why" question:

Early on, the Python developers thought this was a convenient way to write to files.

Since then, they've added stdout redirection, and more powerful file and string-formatting APIs, so it's not as useful anymore. And, thanks to other modern features like keyword arguments, and a few decades to think about it, they've come up with a more flexible way to design print as a regular function that doesn't require any special syntax at all. But removing it would break backward compatibility, so it couldn't be removed until 3.0.

And it was removed in 3.0; you're only still seeing it because you're using an older version.

If you want the new print function in 2.7, however, you can use a future statement: from __future__ import print_function. But that will of course break print >>foo, spam; you'll have to rewrite it as print(spam, file=foo).

Outras dicas

In Python 2, print is a statement (not a function), and statements can make up any goofy syntax they like ;-) The >> here has nothing to do with the right shift operator - it's a gimmick specific to the print statement.

This is widely viewed as ugly, and in Python 3 print is a builtin function (instead of a statement), and to specify a file to which to print Python 3 adds an optional file= argument to the print() function.

It is additional syntax; the compiler looks for >> after a print statement:

>>> import dis
>>> def print_redirected(fh, msg):
...     print >>fh, msg
... 
>>> dis.dis(print_redirected)
  2           0 LOAD_FAST                0 (fh)
              3 DUP_TOP             
              4 LOAD_FAST                1 (msg)
              7 ROT_TWO             
              8 PRINT_ITEM_TO       
              9 PRINT_NEWLINE_TO    
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE        
>>> def print_direct(msg):
...     print msg
... 
>>> dis.dis(print_direct)
  2           0 LOAD_FAST                0 (msg)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE        

The >> results in different bytecode; PRINT_ITEM_TO instead of PRINT_ITEM.

This is the result of the Python grammar explicitly allowing for the extended syntax:

print_stmt: 'print' ( [ test (',' test)* [','] ] |
                      '>>' test [ (',' test)+ [','] ] )

At no point does the compiler interpret the >> as a right-shift operator.

Redirecting print output with this syntax is little used; you can just write directly to the file, or reassign to sys.stdout instead. The simple formatting options the print statement offers can easily be replicated using (much more powerful) string formatting in any case.

Python 3's print() function accepts a file keyword argument to achieve the same functionality.

Your question is answered in a duplicate post. Quoted:

print also has an extended form, defined by the second portion of the syntax described above. This form is sometimes referred to as “print chevron.” In this form, the first expression after the >> must evaluate to a “file-like” object, specifically an object that has a write() method as described above. With this extended form, the subsequent expressions are printed to this file object. If the first expression evaluates to None, then sys.stdout is used as the file for output.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top