Pie*_*e D 9 javascript python ipython-notebook
有没有办法让函数(由IPython Notebook单元调用)检索JavaScript变量的内容(例如IPython.notebook.notebook_path
,其中包含当前笔记本的路径)?
直接在单元格中编写时,以下情况很有效(例如,基于此问题及其注释):
from IPython.display import display,Javascript
Javascript('IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'");')
Run Code Online (Sandbox Code Playgroud)
但是,如果我试图把它放在一个函数中,那就会崩溃:
# 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
Run Code Online (Sandbox Code Playgroud)
(是的,我一直试图让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)
Run Code Online (Sandbox Code Playgroud)
细胞[2]:
print(my_out)
Run Code Online (Sandbox Code Playgroud)
这有效并产生预期的效果hello world
.但是如果你合并两个单元格,它就不起作用(NameError: name 'my_out' is not defined
).
我认为问题与 Javascript 是异步有关,而 python 不是。通常你会认为 Javascript(""" python cmd """) 命令被执行,然后你的打印语句应该按预期正常工作。但是,Javascript 命令被触发但未执行。最有可能是在单元格 1 执行完全完成后执行。
我用睡眠功能尝试了你的例子。没有帮助。
通过在 my_js 中但在 kernel.execute 行之前添加警报语句,可以很容易地看到 asnyc 问题。即使在尝试执行 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)
Run Code Online (Sandbox Code Playgroud)
笔记本中还有其他 javascript 实用程序,如 IPython.display.display_xxx,它们从显示视频到文本对象不等,但即使是文本对象选项也不起作用。
有趣的是,我用我的 webgl canvas 应用程序测试了这个,它在 HTML5 画布上显示对象;display.display_javascript(javascript object) 工作正常(这是一个looong html5文档)而输出的两个单词不显示?!也许我应该将输出嵌入画布应用程序的某个地方,以便它显示在画布上:)
小智 5
我写了一个相关的问题(Cannot get Jupyter Notebook to access javascriptvariables)并想出了一个可以完成这项工作的技巧。它利用了 Python 中的输入(提示)命令确实会阻塞执行循环并等待用户输入的事实。所以我查看了 Javascript 端是如何处理的,并在那里插入了拦截代码。
拦截代码为:
import json
from IPython.display import display, Javascript
display(Javascript("""
const CodeCell = window.IPython.CodeCell;
CodeCell.prototype.native_handle_input_request = CodeCell.prototype.native_handle_input_request || CodeCell.prototype._handle_input_request
CodeCell.prototype._handle_input_request = function(msg) {
try {
// only apply the hack if the command is valid JSON
console.log(msg.content.prompt)
const command = JSON.parse(msg.content.prompt);
const kernel = IPython.notebook.kernel;
// return some value in the Javascript domain, depending on the 'command'.
// for now: specify a 5 second delay and return 'RESPONSE'
kernel.send_input_reply(eval(command["eval"]))
} catch(err) {
console.log('Not a command',msg,err);
this.native_handle_input_request(msg);
}
}
"""))
Run Code Online (Sandbox Code Playgroud)
拦截代码会检查输入提示是否是有效的 JSON,在这种情况下,它会根据参数执行操作command
。在本例中,它运行 commem["eval"] javascript 表达式并返回结果。运行此单元格后,您可以使用:
notebook_path = input(json.dumps({"eval":"IPython.notebook.notebook_path"}))
Run Code Online (Sandbox Code Playgroud)
我必须承认,这确实是一种黑客行为。
好的,我找到了解决该问题的方法:从 Javascript 调用 Python 函数并让它执行我需要的所有操作,而不是将名称返回到“上方”并在那里使用该名称。
作为背景:我和我的同事有很多实验笔记本;我们尝试了一段时间并尝试各种事情(在机器学习背景下)。在每次变化/运行结束时,我想保存笔记本,将其复制到反映时间的名称下,将其上传到 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)}
Run Code Online (Sandbox Code Playgroud)
并在一个单独的文件中,例如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())
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2640 次 |
最近记录: |