【问题标题】:Why/how does Python's print built-in allow the ">>" operator? [duplicate]为什么/如何 Python 的 print 内置允许“>>”运算符? [复制]
【发布时间】:2013-09-16 21:13:37
【问题描述】:

我四处搜索,在这个网站或其他地方都找不到这个问题的答案(搜索涉及标点符号的主题总是一个挑战)。

我在 Python 标准库 (here) 中查找 StringIO,其中一个示例是这样的(摘录):

import StringIO

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

&gt;&gt; 运算符如何或为什么在这里工作?据我所知(而且我不是 Python 专家),这是正确的移位运算符。我想也许StringIO 会覆盖__rshift__ 或其他东西,但StringIO 的来源并没有背叛任何这样的事情。

我还没有四处查看print 内置是如何实现的,但是通过初始搜索我无法弄清楚它是如何工作的。有人吗?

【问题讨论】:

  • 呵呵,找错地方的经典案例。应该查看 print 的文档 :-) 感谢您的回答!

标签: python operators operator-overloading built-in


【解决方案1】:

这真的是几个问题合二为一。


首先,“如何”的问题:

&gt;&gt; 标记在这里实际上不是运算符;它是print 语句语法的一部分,如here 所述。语法是:

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

… 语义是:

这种形式有时被称为“print chevron”。在这种形式中,&gt;&gt; 之后的第一个表达式必须计算为“类文件”对象,特别是具有上述 write() 方法的对象。使用此扩展形式,后续表达式将打印到此文件对象。


第二,“为什么”问题:

早期,Python 开发人员认为这是一种写入文件的便捷方式。

从那时起,他们添加了stdout redirection,以及更强大的文件和字符串格式化 API,所以它不再那么有用了。而且,多亏了关键字参数等其他现代特性,以及几十年来的思考,他们提出了一种更灵活的方法来将print 设计为一个不需要任何特殊语法的常规函数​​。但是删除它会破坏向后兼容性,因此直到 3.0 才能删除它。

并且在 3.0 中被移除;您仍然看到它只是因为您使用的是旧版本。

但是,如果您想要 2.7 中的新 print 函数,您可以使用 future statement: from __future__ import print_function。但这当然会破坏print &gt;&gt;foo, spam;您必须将其重写为print(spam, file=foo)

【讨论】:

  • 感谢@abarnert 的解释。您能否也请添加指向您所指的“stdout 重定向”的链接?想在我越过 Python 3 桥(很快)时阅读它。
  • @scorpiodawg: stdout redirection 只是设置sys.stdout = otherfile。我相信它是在 Python 1.5 中添加的,或者类似的古老的东西,所以你今天已经可以使用它了。但这通常不是您想要的答案。
【解决方案2】:

在 Python 2 中,print 是一个语句(不是函数),并且语句可以构成他们喜欢的任何愚蠢的语法 ;-) 这里的 &gt;&gt; 与右移位运算符无关 - 这是一个噱头特定于print 语句。

这被广泛认为是丑陋的,在 Python 3 中print 是一个内置函数(而不是语句),并且要指定要打印到的文件,Python 3 将可选的 file= 参数添加到 @987654326 @函数。

【讨论】:

    【解决方案3】:

    是附加的语法;编译器在print 语句之后查找&gt;&gt;

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

    &gt;&gt; 产生不同的字节码; PRINT_ITEM_TO 而不是 PRINT_ITEM

    这是Python grammar 明确允许扩展语法的结果:

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

    编译器绝不会将&gt;&gt; 解释为右移运算符。

    很少使用这种语法重定向打印输出;您可以直接写入文件,或重新分配给sys.stdout。在任何情况下,print 语句提供的简单格式化选项都可以使用(更强大的)string formatting 轻松复制。

    Python 3 的 print() function 接受 file 关键字参数来实现相同的功能。

    【讨论】:

    • 非常方便的答案;我很伤心,但我接受了另一个,因为它也帮助我理解了“为什么”,但如果我能接受另一个,就是这样:-)
    • @scorpiodawg:你可能无法接受两个答案,但你可以投票赞成,我认为这个补充的足够多,绝对值得投票。
    • @scorpiodawg:您必须接受被认为对您最有帮助的答案;例如,abarnert 添加了一些有趣的“为什么”背景。 :-)
    【解决方案4】:

    您的问题已在duplicate post 中得到解答。 引用:

    print 还有一个扩展形式,由 上面描述的语法。这种形式有时被称为“打印 雪佛龙。”在这种形式中,>> 之后的第一个表达式必须 评估为“类文件”对象,特别是具有 如上所述的 write() 方法。通过这种扩展形式, 随后的表达式将打印到此文件对象。如果第一个 表达式的计算结果为无,然后 sys.stdout 用作文件 输出。

    【讨论】:

      猜你喜欢
      • 2014-12-03
      • 1970-01-01
      • 1970-01-01
      • 2012-10-30
      • 1970-01-01
      • 2014-10-09
      • 1970-01-01
      • 2018-05-17
      相关资源
      最近更新 更多