为什么我不能使用 ipywidgets class 在 jupyter lab 中打印?

why cannot I print in jupyter lab using ipywidgets class?

我使用 ipyvuetify 库在 Jupyter 环境中创建仪表板。该库运行得非常好,但我正在与 Jupyterlab 和 voila 作斗争,它们在这个问题上似乎具有相同的行为:

假设我想创建一个小部件,当点击它时会打印一条消息:

import ipyvuetify as v 

class Test(v.Btn):
    
    def __init__(self, msg):
        
        self.msg = msg
        
        super().__init__(children=['click'])
        
        self.on_event('click', self._on_click)
        
    def _on_click(self, widget, event, data):
        
        print(self.msg)
        
        return
    
btn = Test(toto)
btn

如果我 运行 来自 Jupyter Notebook 的这段代码,一切正常,msgbtn 单元格输出之后打印。如果我在 Jupyterlab 中执行相同的操作,则打印语句最终会出现在日志中。

现在如果 运行 :

btn._on_click(None, None, None)

msg 打印在 Jupyterlab 和 Jupyter Notebook 中。

有人可以向我解释为什么存在行为差异,以及如何确保我的打印语句最终出现在主工作流中而不是出现在日志中吗?

事实上,JupyterLab 实现了一种不同于 Jupyter Notebook 的机制来捕获输出,通过 ipywidget 的 Output widget:

import ipyvuetify as v
import ipywidgets as w

class Test(v.Btn):
    output = w.Output()
    def __init__(self, msg):
        
        self.msg = msg
        
        super().__init__(children=['click'])
        
        self.on_event('click', self._on_click)
        
    @output.capture()
    def _on_click(self, widget, event, data):
        
        print(self.msg)
        
        return

    def _ipython_display_(self):
        display(super(),self.output)

    
btn = Test('toto')
btn

Ipywidget documentation:通过在 print() 上使用上下文管理器 with self.output: 或 [=15],_on_click 的输出被定向到 output =] 装饰器捕获 _on_click 函数(上面的示例)产生的所有输出。

https://github.com/jupyterlab/jupyterlab/issues/3151#issuecomment-339476572中的一些解释:

We kludged a backwards-compatibility workaround in the classic notebook, but we didn't in jupyterlab. Part of the reason is that it is much harder to write kludgy workarounds in jlab :).

Essentially, the technical issue is that a widget comm message from the browser to the client would need to set the output callback to append output to the current output area - but IIRC it's hard from a mime renderer to get a handle on the output area that contains it.