VSCode Jupyter print 函数输出在错误的单元格(cell)

问题描述

最近在复现一个开源项目时,发现执行过该项目中的代码单元格后,其余单元格的print函数输出也会续在该单元格后。而正常情况下print函数输出应该位于其所属的单元格。下图中,我将出现问题的单元格执行后清空了输出,但是在其他单元格执行 print 函数后,输出还是会打印到该单元格后。而在执行该单元格前 print 功能表现正常。重启电脑无效。

原因

一开始是以为是bug,但是重启电脑都没有看到问题解决,推测多半是正常的原因。而出现问题的单元格是引用开源代码,内部执行逻辑较为复杂,从函数内部找原因耗时较久。

于是突然想到是不是 print 的输出流定位错误了,于是搜了一下print的默认输出流。

In Python, the default output stream for the print() function is sys.stdout.

于是就打印一下 stdout。

import sys
print(sys.stdout)

输出结果如下:

`<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'> `

看上去好像没啥问题?同样的代码新建了一个文件测试,得到的输出如下:

`<ipykernel.iostream.OutStream object at 0x7fd1ed6f5720>`

果然是有问题的。

我尝试了直接获取原来的默认的 ipykernel 的 OutStream,翻了官方的源码[1],没有找到直接获取 OutStream 的方法。花了一小段时间折腾出了下面的代码,自己新建一个 stream 。能用但是用warning,不知道有没有隐藏风险,再次记录一下:

import sys
from IPython.core.getipython import get_ipython
from ipykernel.iostream import OutStream
kernel = get_ipython().kernel
default_out = OutStream(kernel.session, kernel.iopub_socket, name='stdout')
sys.stdout = default_out

会提示 warning:

/tmp/ipykernel_3746745/352382136.py:2: DeprecationWarning: Since IPykernel 4.3, OutStream should be created with IOPubThread, not <ipykernel.iostream.BackgroundSocket object at 0x7fd1ed6f4790> default_out = OutStream(kernel.session, kernel.iopub_socket, name='stdout')

测试了一下不太行。所以就只有朴素的两种解决方案列在下面了。

解决方案

1. 避免 sys.stdout 的操作

检查出现问题的单元格所调用的代码,你应该最终能找到对 sys.stdout 做操作的代码。以我的情况为例,问题的原因是下面的代码。

大概是因为代码的原作者中间调用了一部分输出很多的代码,懒得处理就直接把stdout指向虚空,跑完了再改回来,但是 sys.__stdout__ 并不是 Jupyter 默认的 out stream,所以就回不来了。

第一种思路就是把这里做一些处理(注释或删除),取消掉对 sys.stdout 的操作。

2. 处理 sys.stdout 前备份,操作后还原

另一种思路则是备份默认的 Jupyter OutStream,在执行代码块前将 sys.stdout 保存到一个临时变量中,然后执行结束后再将临时变量的值赋回给 stdout。

original_stdout = sys.stdout
# 原有的造成问题的代码
# xxx
sys.stdout = original_stdout

备注

这个问题非常少见,谷歌也没有找到类似的情况,遇到这种情况也是非常难了。但是解决方案其实很简单,做个备份事后回复就好。

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-06 10:10:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-06 10:10:05       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-06 10:10:05       82 阅读
  4. Python语言-面向对象

    2024-01-06 10:10:05       91 阅读

热门阅读

  1. Python访问ElasticSearch

    2024-01-06 10:10:05       55 阅读
  2. 【node.js】使用nvm切换node环境

    2024-01-06 10:10:05       66 阅读
  3. ubuntu和centos设置永久路由route -n

    2024-01-06 10:10:05       60 阅读
  4. NLP基础——TF-IDF

    2024-01-06 10:10:05       54 阅读
  5. WPF 如何知道当前有多少个 DispatcherTimer 在运行

    2024-01-06 10:10:05       51 阅读
  6. JVM面试系列-03

    2024-01-06 10:10:05       43 阅读
  7. 牧马人K87调节键盘灯光模式

    2024-01-06 10:10:05       57 阅读
  8. Es 学习记录

    2024-01-06 10:10:05       63 阅读