Jupyter:编写一个自定义魔法,修改其所在单元格的内容

时间:2016-06-24 19:21:00

标签: python ipython-notebook jupyter jupyter-notebook

在Jupyter笔记本中,有一些内置的魔法可以改变笔记本电脑的内容。例如,%load magic将当前单元格的内容替换为文件系统上文件的内容。

如何编写一个类似的自定义魔术命令?

到目前为止,我已经向stdout打印了一些东西

def tutorial_asset(line):
    print('hello world')


def load_ipython_extension(ipython):
    ipython.register_magic_function(tutorial_asset, 'line')

我可以使用%load_ext tutorial_asset加载它。但是从那里我迷失了。

[编辑]:

我找到了进入交互式shell实例的方法:

  @magics_class
  class MyMagics(Magics):

      @line_magic
      def tutorial_asset(self, parameters):
          self.shell

self.shell对象似乎可以完全访问笔记本中的单元格集,但我可以找到修改单元格的唯一方法是执行self.shell.set_next_input('print("hello world")')。这是不够的,因为在Jupyter笔记本中,输入单元格被跳过,并且它不会覆盖输入单元格,而是在它之后创建一个新的输入单元格。

这没关系,但是如果我第二次运行笔记本,它会创建另一个加载了相同文件的输入单元,这很烦人。我可以只加载一次,比如检查内容是否已经在下一个单元格中了吗?

1 个答案:

答案 0 :(得分:10)

编辑 :经过一番进一步的挖掘后,我发现笔记本电脑的当前版本无法兼顾。

嗯,这有点棘手......看看IPython代码,如果你想要替换单元格,你需要使用set_next_input,如果你真的想要,你需要run_cell运行一些代码。但是,我无法让两者同时工作 - 看起来set_next_input总是胜利。

深入研究代码,网络前端支持set_next_input上的optional clearing of the output。但是,kernel doesn't yet support setting this flag(因此输出将始终被清除为默认操作)。要做得更好,需要补丁到ipykernel。

我最好的是以下代码,使用jupyter notebook 4.2.1版本:

from __future__ import print_function
from IPython.core.magic import Magics, magics_class, line_magic

@magics_class
class MyMagics(Magics):

    @line_magic
    def lmagic(self, line):
        "Replace current line with new output"
        raw_code = 'print("Hello world!")'
        # Comment out this line if you actually want to run the code.
        self.shell.set_next_input('# %lmagic\n{}'.format(raw_code), replace=True)
        # Uncomment this line if you want to run the code instead.
        # self.shell.run_cell(raw_code, store_history=False)

ip = get_ipython()
ip.register_magics(MyMagics)

这为您提供了一个魔术命令lmagic,它将替换当前单元格或运行raw_code,具体取决于您注释掉的代码位。