如何理解Python中的sys.stdout和sys.stderr

10

我有以下简单的Python代码。

stdout = sys.stdout
stderr = sys.stderr

try:
   # Omitted

finally:
  sys.stdout = stdout

在搜索后,我发现sys.stdinsys.stdoutsys.stderr是与解释器的标准输入标准输出标准错误流相对应的文件对象。因此,我的猜测是我们首先将sys.stdoutsys.stderr分配给变量stdoutstderr

然后,即使在try语句中出现异常,我们也能始终获得sys.stdout吗?这正确吗?我觉得我仍然很困惑。


3
无论发生了什么情况?你的问题或者试图实现什么不清楚。 - pvg
1个回答

32

在常规的C程序中,默认情况下有三个打开的"文件": stdin、stdout和stderr。当您在C中进行输入和输出时,默认情况下它们来自stdin和stdout。但是,您也可以在代码需要文件时使用它们,或重新分配它们以成为新文件。

Python试图“模仿”C的这种行为。当您在Python中使用print()时,您的文本将被写入Python的sys.stdout。当您使用input()时,它来自于sys.stdin。异常被写入sys.stderr

您可以重新分配这些变量,以将代码的输出重定向到除了stdout之外的文件。这非常类似于shell重定向,如果您熟悉这方面的知识的话。您可能会这样做的原因是记录程序的输出或使代码“安静”,即不向stdout发送输出。所以,在您的例子中:

stdout = sys.stdout

try:
    sys.stdout = open('file.txt', 'w')
    print('blah')
    # etc
finally:
    sys.stdout.close()  # close file.txt
    sys.stdout = stdout
    sys.stderr = stderr

这段代码不会在控制台打印任何东西,但它会将"blah"写入名为file.txt的文本文件中。为了使这种操作更少出错,Python 提供了 sys.__stdin__sys.__stdout__,它们始终保存 sys.stdinsys.stdout 的原始值。可以使用以下代码简化上述代码:

try:
    sys.stdout = open('file.txt', 'w')
    print('blah')
    # etc
finally:
    sys.stdout.close()  # close file.txt
    sys.stdout = sys.__stdout__
Python之所以同时拥有stdout__stdout__主要是为了方便,这样您就不必创建一个变量来备份stdout了。 然而,我建议您不要养成重新分配stdout的习惯。这种方式很容易搞砸事情!如果您想保存代码的输出,可以使用shell重定向。如果您想能够记录程序正在做什么,可以看一下Python的logging模块。 如果您希望代码更加安静,请给你的函数一个quiet=False参数,这样您就可以在需要时关闭它们!很少有真正的“需要”重新分配stdout等。 Python允许您这样做,因为Python赋予程序员很多控制权,并期望他们对此负责。如果您真的想这样做,可以像这样操作:
>>> import random
>>> random.random = lambda: 1
>>> random.random()
1
>>> random.random()
1

1
那么,在Python中,“sys.stdin”和“sys._stdin”有什么区别呢? - ntough
3
我更新了答案并添加了更多信息。我不小心给你错误的信息,它是“__stdout__”,而不是“_stdout”!此外,区别在于print()使用stdout,而__stdout__作为备用选项存在,以防您“丢失”原始值。 - brenns10
1
帮我理解什么时候内容会被写入屏幕。你说“异常会被写入sys.stderr。”但是,当我的代码崩溃时,它总是打印到终端...这是否意味着显示到终端来自于sys.errsys.stdout的内容联合? - Charlie Parker

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