溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python怎么實現(xiàn)自定義Jupyter魔法命令

發(fā)布時間:2022-08-26 11:17:04 來源:億速云 閱讀:209 作者:iii 欄目:開發(fā)技術(shù)

今天小編給大家分享一下Python怎么實現(xiàn)自定義Jupyter魔法命令的相關(guān)知識點,內(nèi)容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

相信大家都用過 jupyter,也用過里面的魔法命令,這些魔法命令都以 % 或者 %% 開頭,我們舉個例子。

Python怎么實現(xiàn)自定義Jupyter魔法命令

用法還是比較簡單的,但是我們能不能自定義魔法命令呢?毫無疑問是可以的,因為上面的 %%cython 就是 Cython 模塊自定義的。

所以命令可以是 jupyter 內(nèi)置的,比如 %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>,然后就會調(diào)用這個 hello 方法
        參數(shù) line 就是 %hello 后面的代碼
        """
        print(f"line: {line}")

    @cell_magic
    def world(self, line, cell):
        """
        在 jupyter 中就可以使用如下命令,比如:
        %%world
        <Your Code>
        <Your Code>
        ...

        然后就會調(diào)用這個 world 方法
        參數(shù) cell 就是 %%world 下面整個單元格的代碼

        然后還有一個參數(shù) line,它表示 %%world 所在行后面的代碼
        但對于 %% 開頭的命令來說,我們一般都會新起一行,然后寫代碼
        所以 line 這個參數(shù)暫時用不到
        """
        print(f"line: \n{line}")
        print("-----------------")
        print(f"cell: \n{cell}")


# 必須定義 load_ipython_extension 函數(shù)
# %load_ext 本質(zhì)上也是加載一個模塊
# 但它會自動調(diào)用該函數(shù)
def load_ipython_extension(ip):
    # 在函數(shù)內(nèi)部,我們將類 MagicOrder 注冊進去
    # 然后就可以使用它內(nèi)部的魔法命令了
    ip.register_magics(MagicOrder)

# 如果不定義此函數(shù),那么使用 %load_ext 加載時會報錯
# The xxx module is not an IPython extension.

當前模塊叫 main.py,我們來測試一下:

Python怎么實現(xiàn)自定義Jupyter魔法命令

結(jié)果沒有問題,但說實話對于 %% 開頭的命令來說,我們很少會在它后面寫代碼,基本都是新起一行,就像下面這個樣子。

Python怎么實現(xiàn)自定義Jupyter魔法命令

自定義命令我們已經(jīng)實現(xiàn)了,并且也知道怎么獲取輸入的代碼了,下面要做的就是執(zhí)行它。而將字符串當成代碼執(zhí)行,我們可以使用內(nèi)置函數(shù) exec。

@magics_class
class MagicOrder(Magics):

    @line_magic
    def hello(self, line):
        exec(line)

    @cell_magic
    def world(self, line, cell):
        exec(cell)

代碼的其它部分不變,然后你覺得接下來調(diào)用魔法命令會執(zhí)行成功嗎?我們測試一下:

Python怎么實現(xiàn)自定義Jupyter魔法命令

神奇的地方出現(xiàn)了,雖然命令執(zhí)行成功了,但執(zhí)行完之后,告訴我們變量未定義。其實原因很好想,我們調(diào)用 exec 的時候沒有指定名字空間,那么默認會影響 exec 函數(shù)所在的名字空間,即 hello 和 world 函數(shù)的名字空間。

當打開一個 jupyter 的時候,內(nèi)部相當于啟動了一個 shell,所以在調(diào)用 exec 的時候,應(yīng)該將整個 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 當中執(zhí)行代碼
        exec(line, local_ns, local_ns)

    @needs_local_scope
    @cell_magic
    def world(self, line, cell, local_ns):
        # 或者通過 needs_local_scope 裝飾器
        # 這樣在調(diào)用函數(shù)的時候,會額外傳遞一個 local_ns 參數(shù)
        # 該參數(shù)和 self.shell.user_ns 等價
        exec(cell, local_ns, local_ns)

def load_ipython_extension(ip):
    ip.register_magics(MagicOrder)

然后再來測試一下:

Python怎么實現(xiàn)自定義Jupyter魔法命令

此時就沒有任何問題了。

下面我們模仿 jupyter 的 %time 命令,實現(xiàn)一個 %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)}")

測試一下:

Python怎么實現(xiàn)自定義Jupyter魔法命令

結(jié)果沒有問題,是我們想要的結(jié)果。

最后再來看看如何設(shè)置可選參數(shù),舉一個 Cython 的例子:

Python怎么實現(xiàn)自定義Jupyter魔法命令

我們說對于以 %% 開頭的命令,應(yīng)該新起一行,在它的下面寫代碼。而之所以新起一行,是因為命令所在的行,要用于設(shè)置可選參數(shù)。那么問題來了,如何設(shè)置指定的可選參數(shù)呢?

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",用于指定參數(shù)的名字
    # 后續(xù)便可以通過 name 字段來獲取該參數(shù)的值
    @magic_arguments.argument(
        "-n", "--name", dest="name", default="satori"
    )
    # "-" 和 "--" 可以只出現(xiàn)一個,并且默認解析得到的是字符串
    # 而 age 我們希望是整數(shù),所以指定 type 為 int
    # 解析完參數(shù)之后,會自動調(diào)用 int 進行轉(zhuǎn)化
    # 如果不指定該參數(shù),則使用 default
    # 而這里沒有 default,那么結(jié)果就是 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 就是可選參數(shù),cell 就是代碼塊
        exec(cell, local_ns, local_ns)
        # 解析參數(shù)
        args = magic_arguments.parse_argstring(
            self.order, line)
        # 打印
        print(args)


def load_ipython_extension(ip):
    ip.register_magics(MagicOrder)

我們測試一下:

Python怎么實現(xiàn)自定義Jupyter魔法命令

還是很簡單的,而且這里的參數(shù)解析和 argparse 模塊非常類似,可以自己看一下。

以上就是“Python怎么實現(xiàn)自定義Jupyter魔法命令”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI