您好,登錄后才能下訂單哦!
今天小編給大家分享一下Python怎么實現自定義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 模塊非常類似,可以自己看一下。
以上就是“Python怎么實現自定義Jupyter魔法命令”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。