sys.stdout.write和print有什么区别?

511

在何种情况下,sys.stdout.write()print更优?

(例如:更好的性能;更合理的代码)


6
Python的哪个版本?2.x还是3.x? - Mark Byers
老实说,我想了解两者的情况,尽管我没有使用过Python 3。问题已经更新。 - Johanna Larsson
28
请求了解sys.stdout.write()print之间的基本区别(以及Python为什么会有两者)是一个非常合理的问题,并且并不需要示例。原帖中并没有说命令语法令人困惑。 - smci
16个回答

366

print只是一个薄薄的包装器,用于格式化输入(默认情况下在参数之间加上空格,并在末尾换行),并调用给定对象的写入函数。 默认情况下,此对象为sys.stdout,但您可以使用“三角洲形式”传递文件。例如:

print >> open('file.txt', 'w'), 'Hello', 'World', 2+3

在Python 3.x中,print成为了一个函数,但仍然可以通过file参数传递除sys.stdout以外的其他内容。请参阅:https://docs.python.org/2/reference/simple_stmts.html?highlight=print#the-print-statement
print('Hello', 'World', 2+3, file=open('file.txt', 'w'))

请参见https://docs.python.org/zh-cn/3/library/functions.html#print
在Python 2.6+版本中,print仍然是一个语句,但可以作为函数使用。
from __future__ import print_function

更新:Bakuriu评论指出print函数和print语句(以及更一般的函数和语句)之间存在一些小差异。
在评估参数时出现错误的情况下:
print "something", 1/0, "other" #prints only something because 1/0 raise an Exception

print("something", 1/0, "other") #doesn't print anything. The function is not called

85
值得注意的是,print 会在您写入的任何内容后添加一个换行符,而这不会在使用 sys.stdout.write 时发生。 - Michael Mior
7
如果你需要编写适用于 Python 2.x 和 Python 3.x 的双版本代码,那么使用 sys.stdout.write 更为通用。 - andreb
3
你可以在print末尾加上逗号来抑制print附加的换行符:print "this",; print "on the same line as this" - drevicko
10
sys.stdout.write() 也会缓存输入,并且可能不会立即将输入刷新到文件描述符(fd)中。为了确保其表现类似于print函数,您应该添加:sys.stdout.flush() - kerbelp
4
你可以使用print(blah, end="")来避免在打印时换行。 - naught101
显示剩余4条评论

186

print首先将对象转换为字符串(如果它不是字符串)。如果对象不是行首,它还会在对象前面放置一个空格,并在末尾添加换行符。

当使用stdout时,需要自己将对象转换为字符串(例如通过调用“str”),并且没有换行符。

因此,

print 99

等同于:

import sys
sys.stdout.write(str(99) + '\n')

43
提到换行符给你点赞!我认为这是print.write()之间的主要区别。 - Eric O. Lebigot
10
注意:print 命令可以省略换行符。在 Python 2.x 版本中,在结尾处加一个逗号,输出结果会带上一个空格但不会有换行符,例如print 99,;在 Python 3 版本中,使用 print(..., end='') 可以避免添加换行符(并且不会自动添加空格,除非你使用 end=' ')。 - ToolmakerSteve
2
这并不是真的,在Python2.X中,print操作在信号处理程序中的行为略有不同,即在示例中无法用sys.stdout替换print,详情请参见:https://dev59.com/lmTWa4cB1Zd3GeqPB0_y。 - ddzialak
为了更好的性能,我们可以将print(99)等价于:sys.stdout.write(str(99));sys.stdout.write('\n') - Kasra

52

以下是一些示例代码,基于Mark Lutz的《学习Python》一书,用于解决您的问题:

import sys
temp = sys.stdout                 # store original stdout object for later
sys.stdout = open('log.txt', 'w') # redirect all prints to this log file
print("testing123")               # nothing appears at interactive prompt
print("another line")             # again nothing appears. it's written to log file instead
sys.stdout.close()                # ordinary file object
sys.stdout = temp                 # restore print commands to interactive prompt
print("back to normal")           # this shows up in the interactive prompt

在文本编辑器中打开log.txt文件将会显示以下内容:

testing123
another line

1
有没有办法可以同时将内容打印到屏幕和写入文件中? - Devesh Saini
6
@DeveshSaini: 是的,只需要用至少具有write()和flush()函数的代理类来覆盖sys.stdout。我在这里写了一个示例片段(http://hastebin.com/owijihizus.py)。 - ponycat

42
我的问题是是否有情况下,sys.stdout.write()print 更好用。
最近我开发了一个脚本并将其上传到Unix服务器。我的所有调试消息都使用了print语句,但是这些消息在服务器日志中不会显示出来。
这种情况下可能需要使用sys.stdout.write

10
你确定这是print()sys.stdout.write()之间的区别,而不是stdoutstderr之间的区别吗?为了调试,你应该使用logging模块,该模块将消息打印到stderr - ostrokach
1
是的。使用nohup并重定向到.out文件也是如此。 - conner.xyz
2
使用 sys.stdout.flush() 可以帮助。 - suprit chaudhary
如果您使用nohup,默认情况下所有写入到stdoutstderr的内容都将重定向到nohup.out文件中,无论您是使用print还是stdout.write - Zheng Liu
5
这个答案是猜测性的、误导性的/错误的,绝对不应该有40多的赞同 (截至目前为止)。 - Gringo Suave

18

有至少一种情况,你需要使用sys.stdout而不是print。

当你想要覆盖一行而不跳到下一行时,例如绘制进度条或状态消息时,你需要循环遍历类似于:

Note carriage return-> "\rMy Status Message: %s" % progress

并且由于print会添加一个换行符,因此最好使用sys.stdout


4
如果print命令会自动换行,那么为什么不直接使用print('message', end = '')呢? - Apoorv Patne

9
我的问题是,在什么情况下使用sys.stdout.write()比使用print更好?如果您正在编写可以同时写入文件和标准输出的命令行应用程序,那么这很方便。您可以执行以下操作:
def myfunc(outfile=None):
    if outfile is None:
        out = sys.stdout
    else:
        out = open(outfile, 'w')
    try:
        # do some stuff
        out.write(mytext + '\n')
        # ...
    finally:
        if outfile is not None:
            out.close()

这并不意味着您不能使用with open(outfile, 'w') as out:的模式,但有时候值得这样做。


严格来说,你是可以使用with语句的—— def process(output): # ... / if outfile is None: process(sys.stdout) else: with open(outfile, 'w') as out: process(out)(当然要适时添加换行符)。但这样做显然不太优雅。 - anon

6
在Python 2.x中,print语句会对你给它的内容进行预处理,沿途将其转换为字符串,处理分隔符和换行符,并允许重定向到文件。Python 3.x将其转换为函数,但它仍然具有相同的职责。 sys.stdout是一个文件或类似文件的类,它具有用于写入字符串或类似内容的方法。

5

在需要动态打印的情况下,比如在一个长时间的进程中提供信息,这是更好的选择:

import time, sys
Iterations = 555
for k in range(Iterations+1):

    # Some code to execute here ...

    percentage = k / Iterations
    time_msg = "\rRunning Progress at {0:.2%} ".format(percentage)
    sys.stdout.write(time_msg)
    sys.stdout.flush()
    time.sleep(0.01)

2
print(time_msg, end='') 可以替换为sys.stdout.write(time_msg) sys.stdout.flush() - rluts

5
在Python 3中,printsys.stdout.write之间的区别在于,在终端中执行时返回的值也是不同的。在Python 3中,sys.stdout.write返回字符串的长度,而print只返回None
因此,例如在终端中交互式地运行以下代码将打印出该字符串以及其长度,因为在交互式运行时返回并输出了该长度:
>>> sys.stdout.write(" hi ")
 hi 4

3
>>> sys.stdout.write(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected a string or other character buffer object
>>> sys.stdout.write("a")
a>>> sys.stdout.write("a") ; print(1)
a1

观察上面的例子:

  1. sys.stdout.write不会写入非字符串对象,但是print会。

  2. sys.stdout.write在结尾不会添加换行符,但是print会。

如果我们深入了解,

sys.stdout是一个文件对象,可用于print()的输出。

如果未指定print()的文件参数,则将使用sys.stdout


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接