重要

本文档涵盖 IPython 6.0 及更高版本。从 6.0 版本开始,IPython 不再支持与低于 3.3 的 Python 版本(包括所有版本的 Python 2.7)的兼容性。

如果您正在寻找与 Python 2.7 兼容的 IPython 版本,请使用 IPython 5.x LTS 版本并参考其文档(LTS 是长期支持版本)。

定义自定义魔术

定义您自己的魔术函数主要有两种方法:从独立函数和通过继承 IPython 提供的基类:IPython.core.magic.Magics。下面我们展示了可以放置在从配置加载的文件中的代码,例如默认 IPython 配置文件的 startup 子目录中的任何文件。

首先,让我们看看最简单的案例。以下内容展示了如何仅使用普通函数创建行魔术、单元格魔术和同时适用于两种模式的魔术

from IPython.core.magic import (register_line_magic, register_cell_magic,
                                register_line_cell_magic)

@register_line_magic
def lmagic(line):
    "my line magic"
    return line

@register_cell_magic
def cmagic(line, cell):
    "my cell magic"
    return line, cell

@register_line_cell_magic
def lcmagic(line, cell=None):
    "Magic that works both as %lcmagic and as %%lcmagic"
    if cell is None:
        print("Called as line magic")
        return line
    else:
        print("Called as cell magic")
        return line, cell

# In an interactive session, we need to delete these to avoid
# name conflicts for automagic to work on line magics.
del lmagic, lcmagic

您还可以通过继承 IPython.core.magic.Magics 类来创建所有三种类型的魔术。这使您可以创建可能在调用之间保持状态并完全访问主 IPython 对象的魔术

# This code can be put in any Python module, it does not require IPython
# itself to be running already.  It only creates the magics subclass but
# doesn't instantiate it yet.
from __future__ import print_function
from IPython.core.magic import (Magics, magics_class, line_magic,
                                cell_magic, line_cell_magic)

# The class MUST call this class decorator at creation time
@magics_class
class MyMagics(Magics):

    @line_magic
    def lmagic(self, line):
        "my line magic"
        print("Full access to the main IPython object:", self.shell)
        print("Variables in the user namespace:", list(self.shell.user_ns.keys()))
        return line

    @cell_magic
    def cmagic(self, line, cell):
        "my cell magic"
        return line, cell

    @line_cell_magic
    def lcmagic(self, line, cell=None):
        "Magic that works both as %lcmagic and as %%lcmagic"
        if cell is None:
            print("Called as line magic")
            return line
        else:
            print("Called as cell magic")
            return line, cell


# In order to actually use these magics, you must register them with a
# running IPython.

def load_ipython_extension(ipython):
    """
    Any module file that define a function named `load_ipython_extension`
    can be loaded via `%load_ext module.path` or be configured to be
    autoloaded by IPython at startup time.
    """
    # You can register the class itself without instantiating it.  IPython will
    # call the default constructor on it.
    ipython.register_magics(MyMagics)

如果您想创建一个具有不同构造函数并保存其他状态的类,则应始终调用父构造函数并在注册之前自行实例化类

@magics_class
class StatefulMagics(Magics):
    "Magics that hold additional state"

    def __init__(self, shell, data):
        # You must call the parent constructor
        super(StatefulMagics, self).__init__(shell)
        self.data = data

    # etc...

def load_ipython_extension(ipython):
    """
    Any module file that define a function named `load_ipython_extension`
    can be loaded via `%load_ext module.path` or be configured to be
    autoloaded by IPython at startup time.
    """
    # This class must then be registered with a manually created instance,
    # since its constructor has different arguments from the default:
    magics = StatefulMagics(ipython, some_data)
    ipython.register_magics(magics)

注意

在早期 IPython 版本 0.12 及之前,行魔术是使用 define_magic() API 函数创建的。此 API 已在 IPython 0.13 中替换为上述 API,然后在 IPython 5 中完全删除。建议仍然使用 define_magic() 函数的 IPython 扩展的维护人员针对当前 API 调整其代码。

访问用户命名空间和局部作用域

在创建行魔术时,您可能需要访问周围作用域以获取用户变量(例如在函数内调用时)。IPython 提供了 @needs_local_scope 装饰器,可以从 IPython.core.magics 导入。使用 @needs_local_scope 装饰时,将把 local_ns 作为参数传递给魔术。为了方便,@needs_local_scope 也可以应用于单元格魔术,即使单元格魔术不会出现在局部作用域上下文中。

使魔术输出静音

有时,定义一个可通过在要执行的 Python 代码末尾添加分号来禁用的魔术可能很有用,即以与非魔术表达式相同的方式。这可以通过使用装饰器 @output_can_be_silenced 来实现,该装饰器可以从 IPython.core.magics 导入。使用此装饰器时,IPython 将解析魔术使用的 Python 代码,如果最后一个标记是 ;,则魔术创建的输出将不会显示在屏幕上。如果您想查看此装饰器在操作中的示例,请查看 IPython.core.magics.execution.py 中定义的 time 魔术。

完整示例

以下是魔术包的完整示例。您可以使用 setuptools、distutils 或任何其他分发工具(如 flit,适用于纯 Python 包)来分发魔术。

在将魔术作为包的一部分进行分发时,建议的最佳做法是在 load_ipython_extension 中执行注册,如下面的示例所示,而不是直接在模块中执行(如带有 @register_* 装饰器的初始示例中)。这意味着用户需要使用 %load_ext 明确选择加载您的魔术,而不是在导入模块时隐式获取它。如果加载您的魔术有副作用、加载速度慢或可能覆盖具有相同名称的另一个魔术,则这一点尤其重要。

.
├── example_magic
│   ├── __init__.py
│   └── abracadabra.py
└── setup.py
$ cat example_magic/__init__.py
"""An example magic"""
__version__ = '0.0.1'

from .abracadabra import Abracadabra

def load_ipython_extension(ipython):
    ipython.register_magics(Abracadabra)
$ cat example_magic/abracadabra.py
from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic)

@magics_class
class Abracadabra(Magics):

    @line_magic
    def abra(self, line):
        return line

    @cell_magic
    def cadabra(self, line, cell):
        return line, cell