自定义 jupyter 魔法命令

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 自定义 jupyter 魔法命令

相信大家都用过 jupyter,也用过里面的魔法命令,这些魔法命令都以 % 或者 %% 开头,我们举个例子。

用法还是比较简单的,但是我们能不能自定义魔法命令呢?毫无疑问是可以的,因为上面的 %%cython 就是 Cython 模块自定义的。

所以命令可以是 jupyter 内置的,比如 %time,直接拿来就能用;还可以是第三方模块里面的,在 jupyter 通过 %load_ext 加载之后,再嵌入进来。下面就来看看如何自定义魔法命令。

from IPython.core.magic import (
    magics_class,
    Magics,
    line_magic,
    cell_magic
)
@magics_class
class MagicOrder(Magics):
    """
    自定义一个类,类名叫什么无所谓
    但要继承 Magics,并且要被 magics_class 装饰
    """
    @line_magic
    def hello(self, line):
        """
        在 jupyter 中就可以使用如下命令,比如:
        %hello <Your Code>,然后就会调用这个 hello 方法
        参数 line 就是 %hello 后面的代码
        """
        print(f"line: {line}")
    @cell_magic
    def world(self, line, cell):
        """
        在 jupyter 中就可以使用如下命令,比如:
        %%world
        <Your Code>
        <Your Code>
        ...
        然后就会调用这个 world 方法
        参数 cell 就是 %%world 下面整个单元格的代码
        然后还有一个参数 line,它表示 %%world 所在行后面的代码
        但对于 %% 开头的命令来说,我们一般都会新起一行,然后写代码
        所以 line 这个参数暂时用不到
        """
        print(f"line: \n{line}")
        print("-----------------")
        print(f"cell: \n{cell}")
# 必须定义 load_ipython_extension 函数
# %load_ext 本质上也是加载一个模块
# 但它会自动调用该函数
def load_ipython_extension(ip):
    # 在函数内部,我们将类 MagicOrder 注册进去
    # 然后就可以使用它内部的魔法命令了
    ip.register_magics(MagicOrder)
# 如果不定义此函数,那么使用 %load_ext 加载时会报错
# The xxx module is not an IPython extension.

当前模块叫 main.py,我们来测试一下:

结果没有问题,但说实话对于 %% 开头的命令来说,我们很少会在它后面写代码,基本都是新起一行,就像下面这个样子。

自定义命令我们已经实现了,并且也知道怎么获取输入的代码了,下面要做的就是执行它。而将字符串当成代码执行,我们可以使用内置函数 exec。

@magics_class
class MagicOrder(Magics):
    @line_magic
    def hello(self, line):
        exec(line)
    @cell_magic
    def world(self, line, cell):
        exec(cell)

代码的其它部分不变,然后你觉得接下来调用魔法命令会执行成功吗?我们测试一下:

神奇的地方出现了,虽然命令执行成功了,但执行完之后,告诉我们变量未定义。其实原因很好想,我们调用 exec 的时候没有指定名字空间,那么默认会影响 exec 函数所在的名字空间,即 hello 和 world 函数的名字空间。

当打开一个 jupyter 的时候,内部相当于启动了一个 shell,所以在调用 exec 的时候,应该将整个 shell 的名字空间传进去。

from IPython.core.magic import (
    magics_class,
    Magics,
    line_magic,
    cell_magic,
    needs_local_scope
)
@magics_class
class MagicOrder(Magics):
    @line_magic
    def hello(self, line):
        # 通过 self.shell.user_ns
        # 可以拿到当前 shell 的名字空间
        # 注意:包含所有的单元格
        local_ns = self.shell.user_ns
        # 在 local_ns 当中执行代码
        exec(line, local_ns, local_ns)
    @needs_local_scope
    @cell_magic
    def world(self, line, cell, local_ns):
        # 或者通过 needs_local_scope 装饰器
        # 这样在调用函数的时候,会额外传递一个 local_ns 参数
        # 该参数和 self.shell.user_ns 等价
        exec(cell, local_ns, local_ns)
def load_ipython_extension(ip):
    ip.register_magics(MagicOrder)

然后再来测试一下:

此时就没有任何问题了。

下面我们模仿 jupyter 的 %time 命令,实现一个 %my_time,来加深一遍印象。

@magics_class
class MagicOrder(Magics):
    @needs_local_scope
    @line_magic
    def my_time(self, line, local_ns):
        start = time.perf_counter()
        exec(line, local_ns, local_ns)
        end = time.perf_counter()
        print(f"总耗时: {round(end - start, 3)}")

测试一下:

结果没有问题,是我们想要的结果。

最后再来看看如何设置可选参数,举一个 Cython 的例子:

我们说对于以 %% 开头的命令,应该新起一行,在它的下面写代码。而之所以新起一行,是因为命令所在的行,要用于设置可选参数。那么问题来了,如何设置指定的可选参数呢?

from IPython.core.magic import (
    magics_class,
    Magics,
    cell_magic,
    needs_local_scope
)
from IPython.core import magic_arguments
@magics_class
class MagicOrder(Magics):
    @magic_arguments.magic_arguments()
    # 在 jupyter 中可以通过 -n=xxx 或者 --name=xxx
    # 然后是 dest="name",用于指定参数的名字
    # 后续便可以通过 name 字段来获取该参数的值
    @magic_arguments.argument(
        "-n", "--name", dest="name", default="satori"
    )
    # "-" 和 "--" 可以只出现一个,并且默认解析得到的是字符串
    # 而 age 我们希望是整数,所以指定 type 为 int
    # 解析完参数之后,会自动调用 int 进行转化
    # 如果不指定该参数,则使用 default
    # 而这里没有 default,那么结果就是 None
    @magic_arguments.argument(
        "--age", dest="age", type=int
    )
    @magic_arguments.argument(
        "-h", "--hobby", dest="hobby", default=[],
        action="append"
    )
    @needs_local_scope
    @cell_magic
    def order(self, line, cell, local_ns):
        # 显然 line 就是可选参数,cell 就是代码块
        exec(cell, local_ns, local_ns)
        # 解析参数
        args = magic_arguments.parse_argstring(
            self.order, line)
        # 打印
        print(args)
def load_ipython_extension(ip):
    ip.register_magics(MagicOrder)

我们测试一下:

还是很简单的,而且这里的参数解析和 argparse 模块非常类似,可以自己看一下。我这两天发高烧了,难受到爆炸,实在写不下去了

相关文章
|
3月前
|
SQL 数据可视化 数据库
jupyter中那些神奇的第三方拓展魔术命令
jupyter中那些神奇的第三方拓展魔术命令
jupyter中那些神奇的第三方拓展魔术命令
|
3月前
|
机器学习/深度学习 数据挖掘 Shell
Jupyter notebook中5个有趣的魔法命令
Jupyter notebook中5个有趣的魔法命令
|
11月前
|
Docker Python Windows
1行命令搭建自己的python服务器,docker,安装 jupyter
1行命令搭建自己的python服务器,docker,安装 jupyter
161 0
|
Python
Jupyter-notebook 常用魔法命令
本文分享了一些常用到的 Jupyter-notebook 软件的快捷键以及 魔法命令,以供学习
195 0
|
安全 网络安全 双11
【漏洞复现-jupyter_notebook-命令执行】vulfocus/jupyter_notebook-cve_2019_9644
【漏洞复现-jupyter_notebook-命令执行】vulfocus/jupyter_notebook-cve_2019_9644
288 0
【漏洞复现-jupyter_notebook-命令执行】vulfocus/jupyter_notebook-cve_2019_9644
|
存储 IDE 开发工具
9个可以提高Jupyter Notebook开发效率的魔术命令
9个可以提高Jupyter Notebook开发效率的魔术命令
534 0
9个可以提高Jupyter Notebook开发效率的魔术命令
|
数据挖掘 Python
【DSW Gallery】Jupyter魔术命令使用技巧
Jupyter Notebook除了能够执行Python代码之外,还提供一些魔术命令(Magic Command)方便用户简洁地解决标准数据分析中的各种常见问题,本文介绍几个常见的魔术命令使用技巧。
【DSW Gallery】Jupyter魔术命令使用技巧
|
5月前
|
数据采集 机器学习/深度学习 数据可视化
使用Jupyter Notebook进行数据分析:入门与实践
【6月更文挑战第5天】Jupyter Notebook是数据科学家青睐的交互式计算环境,用于创建包含代码、方程、可视化和文本的文档。本文介绍了其基本用法和安装配置,通过一个数据分析案例展示了如何使用Notebook进行数据加载、清洗、预处理、探索、可视化以及建模。Notebook支持多种语言,提供直观的交互体验,便于结果呈现和分享。它是高效数据分析的得力工具,初学者可通过本文案例开始探索。
|
3月前
|
Python
Jupyter Notebook又一利器nbterm,在终端玩notebook!
Jupyter Notebook又一利器nbterm,在终端玩notebook!
|
5月前
|
文字识别 异构计算 Python
关于云端Jupyter Notebook的使用过程与感想
在自学Python时,由于家庭电脑使用冲突和设备老旧,转向云端平台。体验了多个服务:1. 魔搭modelscope(最喜欢,赠送资源丰富,社区活跃),2. Colaboratory(免费GPU,但有时重启,建议用阿里云),3. Deepnote(免费环境有限,但GPT-4代码生成功能强大),4. 飞桨aistudio(适合PaddlePaddle用户),5. ModelArts(曾有免费实例,现难找)。综合来看,阿里云的稳定性与服务更优,尤其是魔搭的自动代码修正功能。对于AIGC,推荐魔搭和付费版PAI-DSW。欢迎分享更多云端Jupyter平台体验。
219 1