【问题标题】:Why do I get a ValueError when explicitly closing stdout?为什么在显式关闭标准输出时会出现 ValueError?
【发布时间】:2012-02-05 08:38:49
【问题描述】:

这里是 Python 新手。我正在编写一个脚本,可以将一些输出转储到文件或标准输出,具体取决于传递给它的参数。在解释参数时,我将open'ed 文件或stdout 分配给名为output_file 的全局变量,脚本的其余部分可以使用它来写入输出,而不管选择了哪种类型的流。在脚本的最后我closeoutput_file。这对于文件流来说是合适的,虽然它对于标准输出来说是多余的,但我使用其他编程语言的经验表明,在程序结束之前立即显式关闭标准输出没有危害

但是,每当 stdout 用于输出(并随后关闭)时,我都会收到“ValueError: 'I/O operation on closed file.'”。我知道这个错误不是由我调用关闭标准输出直接产生的,而是在我的脚本返回后发生的。我的问题是:为什么会发生这种情况,有没有办法手动关闭标准输出而不触发它? (我知道我可以通过仅在选择文件时有条件地关闭流来轻松解决此问题,但我想知道是否/为什么需要这样做。)

很简单的示范sn-p:

from sys import stdout
stdout.close()

【问题讨论】:

  • 请在关闭 stdout() 后检查您对 output_file 的任何操作的代码,或者在此处放置更多代码,因为给定的 sn-p 仅当在 sn- 之后使用 output_file.write(..) 时才会产生 ValueError p.
  • 给定的 sn-p 会自行产生错误。

标签: python python-3.x stdout


【解决方案1】:

问题是在python-3.2 上尝试关闭以刷新标准输出而不检查它是否已关闭。

issue13444 就是关于这个的。

python-2.7fixing patch 之后的版本中不应该有这个问题。

【讨论】:

  • 很高兴听到这并不是因为我不懂 Python。感谢您指出了这一点。 :-)
【解决方案2】:

一旦您以这种方式关闭了stdout,您必须绝对确定没有任何东西会尝试将任何内容打印到stdout。如果有什么,你会得到那个异常。

我的建议是有条件地关闭output_file

if output_file != sys.stdout:
    output_file.close()

编辑这是一个示例,其中sys.stdout 在脚本的最后关闭,但在运行时仍会生成ValueError: 'I/O operation on closed file

import atexit

@atexit.register
def goodbye():
    print "You are now leaving the Python sector."

import sys
sys.stdout.close()

【讨论】:

  • 我的脚本中没有任何内容在调用关闭后打印到标准输出。 (关闭它的调用是脚本中的最后一行。)在我关闭它后,我还能做些什么来防止这个“神秘罪魁祸首”使用标准输出? :-P
  • @nonoitall:当然,您可以抑制它(例如,通过将stdout 分配给某个丢弃所有写入其中的内容的流)。但是,鉴于此时您甚至不知道写给 stdout 的内容是什么,盲目地丢弃该输出似乎是一件相当愚蠢的事情。
  • 任何人 知道写入标准输出的内容是什么吗?即使从您的示例脚本中删除了 atexit 部分,错误仍然会发生。 (见我的 sn-p。)整个脚本中唯一的一行可以是关闭标准输出的调用,并且仍然会抛出错误。 /我想知道为什么。
  • @nonoitall:当你运行一个只包含import sys 的脚本时会发生什么?这会产生任何输出吗? (如果您使用的是 Unix,请运行 python xyz.py | wc 以查看是否全为零,其中 xyz.py 是有问题的脚本)。
  • 我在 Windows 上,所以手边没有 wc,但是只有 import sys 的脚本没有产生任何输出。 (通过命令行将其标准输出重定向到一个文件,结果文件完全为空。)
【解决方案3】:

关闭前可以查看 output_file.closed 文件:

if not output_file.closed:
    output_file.close()

并确保关闭后没有对 output_file 的 I/O 调用。

【讨论】:

  • 不能解决问题。我关闭标准输出的调用不是错误的直接原因;当我关闭它时,标准输出是打开的。在我的脚本返回之后,其他东西试图使用流,导致错误。我想知道其他东西是什么,是否有办法抑制它。
【解决方案4】:

似乎需要两件事来避免这个错误:reset (i) reset stdout; (ii) 不要关闭标准输出,关闭它被重定向到的文件。

f=open(filename, 'w')
sys.stdout = f
print("la la-la"), file = sys.stdout)
f.close()
sys.stdout = sys.__stdout__

此问题的各种解决方案建议在将 stdout 分配给文件之前将“原始”stdout 指针复制到变量(即 original = stdout ... stdout = f),然后再将其复制回来(stdout = original)。但他们忽略了在日常工作中提及最后的手术,这会浪费时间拉扯头发。

找到解决方案here

【讨论】:

    猜你喜欢
    • 2013-11-06
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    相关资源
    最近更新 更多