手动拉取ipywidget值

时间:2017-04-14 23:27:41

标签: ipython ipython-notebook jupyter-notebook ipywidgets

我有这个代码ipython代码:

import ipywidgets as widgets
from IPython.display import display
import time

w = widgets.Dropdown(
    options=['Addition', 'Multiplication', 'Subtraction'],
    value='Addition',
    description='Task:',
)

def on_change(change):
    print("changed to %s" % change['new'])

w.observe(on_change)

display(w)

它按预期工作。当窗口小部件的值更改时,on_change函数将被触发。但是,我想运行一个长计算并定期检查窗口小部件的更新。例如:

for i in range(100):
    time.sleep(1)
    # pull for changes to w here.
    # if w.has_changed:
    #     print(w.value)

我怎样才能做到这一点?

4 个答案:

答案 0 :(得分:0)

我认为您需要使用线程并挂钩到ZMQ事件循环中。这个要点说明了一个例子:

https://gist.github.com/maartenbreddels/3378e8257bf0ee18cfcbdacce6e6a77e

另见https://github.com/jupyter-widgets/ipywidgets/issues/642

答案 1 :(得分:0)

作为参考,我似乎能够用

进行所需的轮询
import IPython
ipython = IPython.get_ipython()
ipython.kernel.do_one_iteration()

(我仍然希望得到一些关于这是否意外或设计的反馈。)

答案 2 :(得分:0)

要详细说明OP的自我回答,这确实可行。它强制小部件在循环中的任意点与内核同步。这可以在访问widget.value之前完成。

因此,完整的解决方案是:

import IPython
ipython = IPython.get_ipython()

last_val = 0
for i in range(100):
    time.sleep(1)
    ipython.kernel.do_one_iteration()
    new_val = w.value
    if new_val != old_val:
        print(new_val)
        old_val = new_val

答案 3 :(得分:0)

对使用的ipython.kernel.do_one_iteration通话略有改善

# Max iteration limit, in case I don't know what I'm doing here...
for _ in range(100):
  ipython.kernel.do_one_iteration()
  if ipython.kernel.msg_queue.empty():
    break

在我的情况下,我有许多UI元素,它们可以在do_one_iteration调用之间多次单击,这将一次处理一次,并且延迟1秒,这可能会很烦人。一次最多处理100个。通过多次捣碎按钮对其进行了测试,现在sleep(1)结束时,它们都获得了处理。