有没有办法让函数(由IPython Notebook单元调用)检索JavaScript变量的内容(例如包含当前笔记本路径的IPython.notebook.notebook_path
)?
直接在单元格中编写时(例如,基于this question及其注释),以下情况很有效:
from IPython.display import display,Javascript
Javascript('IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'");')
但是,如果我试图把它放在一个函数中,那就会崩溃:
# this doesn't work
from IPython.display import display,Javascript
def getname():
my_js = """
IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'");
"""
Javascript(my_js)
return mypath
(是的,我试图在global
脚本和函数内部使mypath
成为my_js
变量。另请注意:不要被先前命令中变量中可能的剩余值所欺骗;为了确保使用mypath = None; del mypath
在调用函数之前重置变量,或者重启内核。)
制定问题的另一种方法是:“IPython.notebook.kernel.execute()
设定的变量的范围(时间和地点)是什么”?
我认为这不是一个无关紧要的问题,可能与IPython用来控制其内核及其变量的机制有关,而且我对此并不了解。以下实验说明了该机制的某些方面。以下工作在两个单独的单元格中完成,但如果两个单元格合并则不起作用:
细胞[1]:
my_out = None
del my_out
my_js = """
IPython.notebook.kernel.execute("my_out = 'hello world'");
"""
Javascript(my_js)
细胞[2]:
print(my_out)
这工作并产生预期的hello world
。但如果你合并这两个单元格,它就不起作用(NameError: name 'my_out' is not defined
)。
我认为这个问题与Javascript是asynchronus有关,而python则没有。通常,您会认为执行了Javascript(“”“python cmd”“”)命令,然后您的打印声明应该按预期正常工作。但是,Javascript命令被触发但未执行。最可能的是它在单元格1执行完全完成后执行。
我尝试了睡眠功能的例子。没有帮助。
通过在我的js中添加alert语句,但在kernel.execute行之前,可以很容易地看到异步问题。即使在尝试执行python命令之前,也应该触发警报。
但是在单元格1中存在print(my_out)语句时,您将再次收到相同的错误而没有任何警报。如果取出打印行,您将看到单元格1中弹出警报。但后来设置了变量my_out。
my_out = None
del my_out
my_js = """
**alert ("about to execute python comand");**
IPython.notebook.kernel.execute("my_out = 'hello world'");
"""
Javascript(my_js)
笔记本中还有其他javascript实用程序,如IPython.display.display_xxx,从显示视频到文本对象不等,但即使文本对象选项也不起作用。
有趣的是,我用我的webgl canvas应用程序对它进行了测试,该应用程序在HTML5画布上显示对象; display.display_javascript(javascript object)工作正常(这是一个looong html5文档),而输出的两个单词没有出现?!也许我应该将输出嵌入到某个地方的canvas应用程序中,所以它显示在画布上:)
好吧,我找到了解决问题的方法:从Javascript调用Python函数并让它完成我需要的所有操作,而不是将名称返回到“above”并在那里使用该名称。
对于背景:我和我的同事有很多实验笔记本;我们试验了一段时间并尝试了各种各样的东西(在机器学习环境中)。在每个变体/运行结束时,我想保存笔记本,将其复制到反映时间的名称,将其上传到S3,从输出中删除它并将其推送到git,记录文件名,注释和结果分数到数据库等等。简而言之,我想自动跟踪我们的所有实验。
这就是我到目前为止所拥有的。在笔记本的底部,我说:
In [127]: import mymodule.utils.lognote as lognote
lognote.snap()
In [128]: # not to be run in the same shot as above
lognote.last
Out[128]: {'file': '/data/notebook-snapshots/2015/06/18/20150618-004408-save-note-exp.ipynb',
'time': datetime.datetime(2015, 6, 18, 0, 44, 8, 419907)}
并在一个单独的文件中,例如mymodule/utils/lognote.py
:
# (...)
from datetime import datetime
from subprocess import call
from os.path import basename, join
from IPython.display import display, Javascript
# TODO: find out where the topdir really is instead of hardcoding it
_notebook_dir = '/data/notebook'
_snapshot_dir = '/data/notebook-snapshots'
def jss():
return """
IPython.notebook.save_notebook();
IPython.notebook.kernel.execute("import mymodule.utils.lognote as lognote");
IPython.notebook.kernel.execute("lognote._snap('" + IPython.notebook.notebook_path + "')");
"""
def js():
return Javascript(jss())
def _snap(x):
global last
snaptime = datetime.now()
src = join(_notebook_dir, x)
dstdir = join(_snapshot_dir, '{}'.format(snaptime.strftime("%Y/%m/%d")))
dstfile = join(dstdir, '{}-{}'.format(snaptime.strftime("%Y%m%d-%H%M%S"), basename(x)))
call(["mkdir", "-p", dstdir])
call(["cp", src, dstfile])
last = {
'time': snaptime,
'file': dstfile
}
def snap():
display(js())
为了增加其他很棒的答案,浏览器试图在nb load上运行jupyter nb javascript魔法有一个细微差别。
要演示:创建并运行以下单元格:
%%javascript
IPython.notebook.kernel.execute('1')
现在保存笔记本,关闭它然后重新打开它。当你这样做时,突然在那个单元格下你会看到一个红色的错误:
Javascript error adding output!
TypeError: Cannot read property 'execute' of null
See your browser Javascript console for more details.
这意味着浏览器已经解析了一些js代码,并尝试运行它。这是chrome中的错误,它可能在不同的浏览器中有所不同。
我不知道为什么这个jupyter javascript魔术单元正在加载运行,为什么jupyter笔记本没有正确转义,但浏览器看到一些js代码,所以它运行它并失败,因为笔记本内核尚不存在!
因此,您必须添加对象存在的检查:
%%javascript
if (IPython.notebook.kernel) {
IPython.notebook.kernel.execute('1')
}
现在加载没问题。
在我的情况下,我需要保存笔记本并在其上运行外部脚本,所以我最终使用此代码:
from IPython.display import display, Javascript
def nb_auto_export():
display(Javascript("if (IPython.notebook) { IPython.notebook.save_notebook() }; if (IPython.notebook.kernel) { IPython.notebook.kernel.execute('!./notebook2script.py ' + IPython.notebook.notebook_name )}"))
在笔记本的最后一个单元格中:
nb_auto_export()