问题描述
在Jupyter笔记本中,有一些内置的魔术可以改变笔记本单元的内容.例如,%load
魔术将当前单元格的内容替换为文件系统上文件的内容.
In a Jupyter notebook there are some built-in magics that change the contents of a notebook cell. For example, the %load
magic replaces the contents of the current cell with the contents of a file on the file system.
如何编写类似功能的自定义魔术命令?
How can I write a custom magic command that does something similar?
到目前为止,我所拥有的内容可以打印出一些标准内容
What I have so far prints something to stdout
def tutorial_asset(line):
print('hello world')
def load_ipython_extension(ipython):
ipython.register_magic_function(tutorial_asset, 'line')
我可以用%load_ext tutorial_asset
加载它.但是从那里我迷路了.
And I can load it with %load_ext tutorial_asset
. But from there I'm lost.
:
我找到了一种进入交互式shell实例的方法:
I've found a way to get to the interactive shell instance:
@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笔记本中,该输入单元格被跳过,并且不覆盖输入单元格,而是在其后创建了一个新的输入单元格.
The self.shell
object seems to give complete access to the set of cells in the notebook, but the only way I can find to modify the cells is to do self.shell.set_next_input('print("hello world")')
. This isn't sufficient because, in a Jupyter notebook, that input cell is skipped, and it doesn't overwrite the input cell, it instead creates a new input cell after it.
这很好,但是如果我第二次运行笔记本,它会创建另一个加载了相同文件的输入单元,这很烦人.通过检查内容是否已经在下一个单元格中,我是否只能加载一次?
This would be fine, but if I run the notebook a second time, it creates another input cell with the same file loaded, which is annoying. Can I have it load only once, say, by checking if the contents are already in the next cell?
推荐答案
EDIT :经过进一步的挖掘,我发现当前的笔记本不能同时实现这两种功能.
EDIT: After a little further digging, I found that the current build of notebook cannot do both.
好吧,这有点棘手...看一下IPython代码,如果要替换单元格,似乎需要使用set_next_input
,而实际上要运行一些代码,则需要使用run_cell
.但是,我不能同时使两者同时工作-看来set_next_input
总是赢.
Well, this is a little tricky... Looking at the IPython code, it looks like you need to use set_next_input
if you want to replace the cell, and run_cell
if you actually want to run some code. However, I can't get both to work at once - it looks like set_next_input
always wins.
深入到代码中,Web前端支持在set_next_input
上可选清除输出.但是,内核尚不支持设置此标志(因此输出将始终被清除为默认操作).为了做得更好,需要对ipykernel进行补丁.
Digging into the code, the web front-end supports optional clearing of the output on set_next_input
. However, the kernel doesn't yet support setting this flag (and so output will always be cleared as the default action). To do better will require a patch to ipykernel.
因此,我拥有的最好的是使用jupyter Notebook版本4.2.1的以下代码:
The best I therefore have is the following code, using jupyter notebook version 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
,具体取决于您注释掉的代码的哪一部分.
This gives you a magic command lmagic
that will either replace the current cell or run the raw_code
depending on which bit of the code you have commented out.
这篇关于Jupyter:编写定制魔术来修改其所在单元格的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!