【问题标题】:redirect sys.stdout to specific Jupyter Notebook cell将 sys.stdout 重定向到特定的 Jupyter Notebook 单元
【发布时间】:2016-11-13 23:07:44
【问题描述】:

Jupyter==4.1.0,Python==2.7.10,IPython==4.2.0

我正在为我的 Jupyter Notebooks 编写一个 SQL UI,并希望合并多线程,以便我可以在一个单元格中运行查询,并在查询运行时继续在其他单元格中工作。

我遇到的问题是,如果我在一个单元格中执行查询,则输出将显示在最后执行的单元格的输出提示中,而不是执行查询的单元格的输出提示中。

我搜索了互联网并发现了this clever trick,但我认为它已经过时并且/或者不再适用于我的 Jupyter 版本。当我运行它时,我只会得到最后一次执行的单元格的输出。因此,如果我同时运行两者,我只会得到最后执行的输出,而不是同时输出打印到单独的单元格。

所以我有我的上下文管理器来设置parent_header:

import sys
import threading
from contextlib import contextmanager

# we need a lock so that other threads don't snatch control
# while we have set a temporary parent
stdout_lock = threading.Lock()

@contextmanager
def set_stdout_parent(parent):
    """a context manager for setting a particular parent for sys.stdout 
    the parent determines the destination cell of the output
    """
    save_parent = sys.stdout.parent_header
    with stdout_lock:
        sys.stdout.parent_header = parent
        try:
            yield
        finally:
            # the flush is important, because that's when the parent_header actually has its effect
            sys.stdout.flush()
            sys.stdout.parent_header = save_parent

我本质上希望能够获取单元格 In[1] 的 parent_header 并将单元格 In[2] 的输出重定向到 In[1] 的输出。

例子:

获取 In[1] 的parent_header

In[1]: t = sys.stdout.parent_header

然后以下代码将运行,但输出应打印到 Out[1](目前,当我运行此代码时没有输出):

In [2]: with set_stdout_parent(t):
            print 'FOO'

应该产生什么:

In[1]: t = sys.stdout.parent_header
Out[1]:'FOO'

【问题讨论】:

  • 我对此的次要修复是在其线程上运行查询并打印出具有唯一 ID 的 HTML 容器,然后当查询完成时,使用 IPython 的 displayJavascript 函数将其附加到适当的 DOM 对象。
  • 如何将输出保存到文件中,然后在另一个单元格中打开并打印该文件?
  • 你试过类似this
  • 这个怎么样:ipykernel.iostream.OutStream?

标签: python ipython jupyter-notebook io-redirection sys


【解决方案1】:

ipywidgets.Output 的文档中有一个关于 interacting with output widgets from background threads 的部分。使用Output.append_stdout 方法不需要锁定。 this answer 中的最后一个单元格可以替换为:

def t1_main():
    for i in range(10):
        output1.append_stdout(f'thread1 {i}\n')
        time.sleep(0.5)


def t2_main():
    for i in range(10):
        output2.append_stdout(f'thread2 {i}\n')
        time.sleep(0.5)

output1.clear_output()
output2.clear_output()
        
t1 = Thread(target=t1_main)
t2 = Thread(target=t2_main)
t1.start()
t2.start()
t1.join()
t2.join()

【讨论】:

    【解决方案2】:

    您可以结合使用ipywidgets.Output (docs) 和锁定:

    jupyter 单元格中的代码:

    # In[1]:
    
    
    from threading import Thread, Lock
    import time
    from ipywidgets import Output
    
    
    # In[2]:
    
    
    output1 = Output()
    output1
    
    
    # In[3]:
    
    
    output2 = Output()
    output2
    
    
    # In[4]:
    
    
    print_lock = Lock()
    def t1_main():    
        for i in range(10):
            with print_lock, output1:
                print('thread1', i)
            time.sleep(0.5)
    
    def t2_main():
        for i in range(10):
            with print_lock, output2:
                print('thread2', i)
            time.sleep(0.5)
    
    output1.clear_output()
    output2.clear_output()
            
    t1 = Thread(target=t1_main)
    t2 = Thread(target=t2_main)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-27
      • 2020-06-02
      • 1970-01-01
      • 1970-01-01
      • 2018-08-09
      • 2015-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多