Jupyter笔记本的标准输出重定向到终端上了。

9
所以我试图将Jupyter笔记本中一些单元格的stdout重定向到一个文件中,使用这个,然后使用这个来取消其余单元格的重定向。第一组单元格的输出像预期的那样被写入了文件中。在取消命令sys.stdout = sys.__stdout__之后,第二组单元格没有任何输出,似乎什么都没做,但后来我意识到它们实际上是被写入了启动笔记本的终端窗口中。

在完全相同的Python环境下,它在Python解释器中运行得非常完美:

(miniconda3-latest) cardamom@pegasus:~/Documents/project1 $ python
Python 3.6.0 |Continuum Analytics, Inc.| (default, Dec 23 2016, 12:22:00) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.stdout = open('stdout.txt', 'w')
>>> print("a")
>>> print("a")
>>> print("a")
>>> sys.stdout = sys.__stdout__
>>> print ("b")
b
>>> print ("b")
b
>>> print ("b")
b
>>> # lots of a's are in the file and no b's

在Jupyter笔记本中采用类似的方法,可以在终端中得到以下内容:
[W 22:05:34.192 NotebookApp] 404 GET /nbextensions/widgets/notebook/js/extension.js (127.0.0.1) 1.71ms referer=http://localhost:8889/notebooks/test_stdout.ipynb
b
b
b

这段代码该如何修改,以便在重置后,b出现在输出单元格下方而不是终端中?
2个回答

12
我所看到的唯一解释是 sys.stdout 不是 sys.__stdout__,而是一个重新路由/修改的文件对象,以便能够将数据放入单元格中(您的评论表明它是一个 ipykernel.iostream.OutStream 实例)。因此,您应该存储 sys.stdout 的引用,而不是重置为 sys.__stdout__
import sys
old_stdout = sys.stdout
sys.stdout = open('stdout.txt', 'w')
...
sys.stdout = old_stdout

请注意,此方法也适用于标准终端。


谢谢,可以了。我从没想过这是可以备份的东西,但是当我查看笔记本中 old_stdout 对象时,它看起来像这样:<ipykernel.iostream.OutStream at 0x7f71eeae6c50> - cardamom
我必须承认,我甚至没有注意到sys.__stdout__的存在。我总是使用我的答案中描述的方法(必须用于像C这样的语言,其中一切都必须手动完成 :))。请注意,您不是在备份它,而是仅存储引用,而不是丢失它。 - Jean-François Fabre
3
当程序被中止时,问题就出现了。Jupyter会记住stdout的状态,如果不重新启动内核就无法恢复。这很不方便。是否有其他方法可以重置stdout并将其重定向到Jupyter笔记本? - Steve

0
为了处理程序执行中止的情况,你可以尝试处理错误。
import sys
nb_stdout = sys.stdout
with open("cell_output.deleteme", 'w') as cl_stdout:
    sys.stdout = cl_stdout
    try:
        print("hello, world!")
        raise Exception("goodbye, cruel world!")
    except Exception as e:
        print(e)
    finally:
        print("cell stdout")
        sys.stdout = nb_stdout
        print("notebook stdout")

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