2

我正在尝试基于 ipythonblocks 创建一些简单的异步执行动画,并且我正在尝试使用clear_output()后跟一个grid.show().

对于文本输出,该技术的基础在线程 IPython Notebooks 的每个单元格输出中进行了讨论,因此我的简单假设是使用相同的方法来隔离 HTML 输出。由于我想用更新后的 HTML 版本反复替换网格,因此我尝试使用它clear_output()来确保只显示一个网格副本。

我验证了这种提议的技术适用于以下单元格的文本输出。首先是上下文管理器。

import sys
from contextlib import contextmanager
import threading

stdout_lock = threading.Lock()
n = 0

@contextmanager
def set_stdout_parent(parent):
    """a context manager for setting a particular parent for sys.stdout
    (i.e. redirecting output to a specific cell). The parent determines
    the destination cell of output
    """
    global n
    save_parent = sys.stdout.parent_header
    # we need a lock, so that other threads don't snatch control
    # while we have set a temporary parent
    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
            n += 1; print("Flushing", n)
            sys.stdout.flush()
            sys.stdout.parent_header = save_parent

然后是测试代码

import threading
import time
class timedThread(threading.Thread):
    def run(self):
        # record the parent (uncluding the stdout cell) when the thread starts
        thread_parent = sys.stdout.parent_header
        for i in range(3):
            time.sleep(2)
            # then ensure that the parent is the same as when the thread started
            # every time we print
            with set_stdout_parent(thread_parent):
                print(i)

timedThread().start()

这提供了输出

0
Flushing 1
1
Flushing 2
2
Flushing 3

所以我修改了代码以清除循环之间的单元格。

import IPython.core.display

class clearingTimedThread(threading.Thread):
    def run(self):
        # record the parent (uncluding the stdout cell) when the thread starts
        thread_parent = sys.stdout.parent_header
        for i in range(3):
            time.sleep(2)
            # then ensure that the parent is the same as when the thread started
            # every time we print
            with set_stdout_parent(thread_parent):
                IPython.core.display.clear_output()
                print(i)

clearingTimedThread().start()

正如预期的那样,单元格的输出区域被反复清除,并最终读取

2
Flushing 6

因此,我认为在使用 ipythonblocks 时使用相同的技术来清除单元格的输出区域是安全的。唉,没有。这段代码

from ipythonblocks import BlockGrid

w = 10
h = 10

class clearingBlockThread(threading.Thread):
    def run(self):
        grid = BlockGrid(w, h)
        # record the parent (uncluding the stdout cell) when the thread starts
        thread_parent = sys.stdout.parent_header
        for i in range(10):
            # then ensure that the parent is the same as when the thread started
            # every time we print
            with set_stdout_parent(thread_parent):
                block = grid[i, i]
                block.green = 255
                IPython.core.display.clear_output(other=True)
                grid.show()
            time.sleep(0.2)

clearingBlockThread().start()

确实会产生所需的最终状态(带有绿色对角线的黑色矩阵),但中间步骤不会出现在单元格的输出区域中。稍微复杂一点(?)这个例子是在 Python 3 上运行的。在发布之前检查我发现预期的行为(一个简单的动画)实际上确实发生在 Python 2.7 下。因此,我想问这是否是我需要报告的问题。

4

0 回答 0