【问题标题】:IPython notebook ~ Using javascript to run python code?IPython notebook ~ 使用javascript运行python代码?
【发布时间】:2015-10-06 15:37:33
【问题描述】:

我正在尝试直接通过javascript执行python代码:

  1. 我在 Chrome 上启动了 IPython Notebook
  2. 我使用 chrome 开发者工具打开了 javascript 控制台。

在 javascript consolde 中,我输入:IPython.notebook.kernel.execute("2+2")

但我得到一个奇怪的输出:"6CEA73CC644648DDA978FDD6A913E519"

有没有办法利用所有可用的 IPython javascript 函数,从 javascript 控制台运行 python 代码,如图所示?我确定有办法,但我已经研究了太久了,我想我会在这里发帖。

(我需要这个在 IPython 之上构建应用程序)

提前致谢!

【问题讨论】:

    标签: javascript python ipython ipython-notebook


    【解决方案1】:

    您可以使用 Jupyter.notebook.kernel.execute() 函数从 JavaScript 调用 Python 代码执行。

    依赖于来自 Craig Dennis 的 gist,您可以将此代码插入 Jupyter 单元并运行它

    %%javascript
    window.executePython = function(python) {
        return new Promise((resolve, reject) => {
            var callbacks = {
                iopub: {
                    output: (data) => resolve(data.content.text.trim())
                }
            };
            Jupyter.notebook.kernel.execute(`${python}`, callbacks);    
        });
    }
    
    function Log_out(r)
    { console.log(r); };
    
    var code = 
    'for i in range(1,6):'+
    '    print( "#" + str(i))';
    
    window.executePython( code )
        .then(result => Log_out(result)); // Log out
    

    结果将输出到浏览器的javascript控制台。

    【讨论】:

    • 为了将大数据帧传输到 javascript,可能需要关闭 pandas 的预览功能: with pandas.option_context("display.max_rows", None, "display.max_columns", None, " display.width", None): print(dataFrame) 另见stackoverflow.com/questions/19124601/…
    【解决方案2】:

    您知道这篇博文吗? http://jakevdp.github.io/blog/2013/06/01/ipython-notebook-javascript-python-communication/

    我认为他使用的确切方式不再有效,但也许它可以让你向前迈出一步

    【讨论】:

    • 谢谢,是的,我在 cmets 中尝试过 +,有适用于 IPython 2.0 和 3.1 的解决方案,但我无法获得任何适用于 IPython 4.0.0 的解决方案(也尝试提出一些解决方案,但无济于事)
    • 也许在 jupyter repo 上的 github 问题中提出这个问题。以这种方式获得帮助的经验很好
    • 感谢您的提示,我会试一试。
    【解决方案3】:

    花了两天时间,这是对我有用的解决方案。

    要运行 Python 代码,我很容易使用“Jupyter.notebook.kernel.execute”。为了得到答案,我在这个链接中找到了有用的信息:https://jupyter-notebook.readthedocs.io/en/stable/comms.html

    from ipykernel.comm import Comm
    
    js_input = [] #case willing to track
    
    def func_edit(cobj,text):
        my_comm = Comm(target_name=cobj) #this is the callback
        my_comm.send('' if  text == '' else 'Return: ' + text)
    
        global js_input
        js_input.append(f'origin={cobj} text={text}')
        
        
        
    from IPython.display import display, HTML
    html = """
    <script>
        var comm_name = "this_control";
        function fcalc(x)
        {
            // here I am passing to the Python function the value to edit and the address for getting the return value
            IPython.notebook.kernel.execute("func_edit('" + comm_name + "','" + x.value + "')")
        }
        Jupyter.notebook.kernel.comm_manager.register_target(comm_name, function(comm, msg) 
            {
              // comm is the frontend comm instance,  msg is the comm_open message, which can carry data
    
                // Register handlers for later messages:
                comm.on_msg(function(msg) { 
                    document.getElementById("out").value = msg.content.data;
                });
                
                //comm.on_close(function(msg) {...});
                //comm.send({'foo': 40}); what is it??
            });
    </script>
    <label for="in">Input:</label>
    <input type="text" id="in" name="in" oninput="fcalc(this)">
    <label for="out">Out:</label>
    <input type="text" id="out">
    """
    display(HTML(html))
    

    【讨论】:

      【解决方案4】:

      为了隔离一个最小可行的实现,我能够使用与ChrCury78 基本相同的方法,通过几个步骤从 IPython 内核获得响应。

      由于我想在 Javascript 中使用从 Python 返回的数据,因此在这些示例中,我只是将消息内容存储在 console 的成员中。 (与 ChrCury78 所做的不同,他将结果推送到笔记本单元的输出。)在我真正的扩展中,我可能只是将它附加到 Jupyter 上的名称,或者可能是我自己创建的对象。

      >> Jupyter.notebook.kernel.comm_manager.register_target("mycomm", (comm, msg) => {comm.on_msg( m => {console.retval = m.content.data})})
      <- undefined
      >> Jupyter.notebook.kernel.execute("from ipykernel.comm import Comm; Comm(target_name='mycomm').send('FOO')")
      <- "{hex UID}"
      >> console.retval
      <- "FOO"
      

      多行 Python 代码也可以正常工作;而且,由于我已经导入了Comm,我不需要再次导入它:

      >> Jupyter.notebook.kernel.execute("l = []\nfor x in range(5):\n  l.append(x)\nComm(target_name='mycomm').send(l)")
      <- "{hex UID}"
      >> console.retval
      <- Array(5) [ 0, 1, 2, 3, 4 ]
      

      如果您想在之后保持内核命名空间不受污染,可以在 Python 命令的末尾添加 del Comm

      我肯定会为这两个操作编写某种包装函数。


      这是安装了 Python 3.9.11 和以下软件包:

      ipykernel                         6.9.2
      ipython                           8.1.1
      ipython-genutils                  0.2.0
      ipywidgets                        7.7.0
      
      jupyter                           1.0.0
      jupyter-client                    7.1.2
      jupyter-console                   6.4.3
      jupyter-contrib-core              0.3.3
      jupyter-contrib-nbextensions      0.5.1
      jupyter-core                      4.9.2
      jupyter-highlight-selected-word   0.2.0
      jupyter-latex-envs                1.4.6
      jupyter-nbextensions-configurator 0.4.1
      jupyterlab-pygments               0.1.2
      jupyterlab-widgets                1.1.0
      
      

      【讨论】:

        猜你喜欢
        • 2017-09-26
        • 1970-01-01
        • 2015-05-04
        • 2021-05-28
        • 1970-01-01
        • 2013-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多