【導(dǎo)語(yǔ)】:IPython 是一個(gè) Python的交互式shell,比默認(rèn)的 Python shell好用得多。它有許多好用的特性,本文將對(duì)一些特性進(jìn)行介紹。
介紹
IPython 是一個(gè)Python的交互式shell,比默認(rèn)的 Python shell好用得多,支持變量自動(dòng)補(bǔ)全,自動(dòng)縮進(jìn),內(nèi)置了許多很有用的功能和函數(shù)。在之前的項(xiàng)目中,我使用 IPython 較多,每當(dāng)在開(kāi)發(fā)中遇到問(wèn)題時(shí),我會(huì)打印每一步的輸出,查找問(wèn)題。完成項(xiàng)目后,我對(duì)之前使用 IPython 的一些經(jīng)驗(yàn)作了總結(jié)。在本文,我將對(duì)之前的總結(jié)作以簡(jiǎn)單介紹。
此外,文中的部分命令配有 gif 圖演示,但由于比較大,沒(méi)法上傳到微信公眾號(hào)。如果有需要 gif 演示動(dòng)圖的小伙伴,請(qǐng)看文末獲取方式。
1. 顯示文檔
?
In?[1]:?import?re In?[2]:?re.findall? Signature:?re.findall(pattern,?string,?flags=0) Docstring: Return?a?list?of?all?non-overlapping?matches?in?the?string. If?one?or?more?capturing?groups?are?present?in?the?pattern,?return a?list?of?groups;?this?will?be?a?list?of?tuples?if?the?pattern has?more?than?one?group. Empty?matches?are?included?in?the?result. File:??????~/.pyenv/versions/3.9.0/lib/python3.9/re.py Type:??????function
?
這是我最喜歡的功能之一。我們可以通過(guò)在任何函數(shù)、模塊、變量的開(kāi)頭或結(jié)尾添加“?”來(lái)顯示其文檔。它被稱為“動(dòng)態(tài)對(duì)象檢查”,通過(guò)使用該特性,我們就可以在不退出終端的情況下來(lái)獲取文檔。在標(biāo)準(zhǔn)的Python交互式解釋器中REPL中,使用help()函數(shù)也能獲取文檔信息,但"?"輸出的文檔可讀性更強(qiáng)。它能將函數(shù)簽名對(duì)象signature、文檔字符串等重要信息高亮顯示。(由于我使用的語(yǔ)法高亮庫(kù)不支持Ipython,因此在這里無(wú)法顯示)
2. 顯示源代碼
?
In?[1]:?import?pandas In?[2]:?pandas.DataFrame?? Init?signature: pandas.DataFrame( ????data=None, ????index:?Optional[Collection]?=?None, ????columns:?Optional[Collection]?=?None, ????dtype:?Union[ForwardRef('ExtensionDtype'),?str,?numpy.dtype,?Type[Union[str,?float,?int,?complex,?bool]],?NoneType]?=?None, ????copy:?bool?=?False, ) Source: class?DataFrame(NDFrame): ????""" ????Two-dimensional,?size-mutable,?potentially?heterogeneous?tabular?data. ????Data?structure?also?contains?labeled?axes?(rows?and?columns). ????Arithmetic?operations?align?on?both?row?and?column?labels.?Can?be ????thought?of?as?a?dict-like?container?for?Series?objects.?The?primary ????pandas?data?structure. ????Parameters ????----------
?
假如我們想查看一個(gè)函數(shù)(或者類/模塊)的源代碼,可以使用兩個(gè)問(wèn)號(hào),例如:function_name??,??function_name。
3. %edit 函數(shù)
3_edit.gif
如果我們想在 IPython 中寫(xiě)一個(gè)功能較復(fù)雜的函數(shù),可以使用 %edit 命令打開(kāi)自己喜歡的編輯器(也可以用 $editor環(huán)境變量設(shè)置編輯器),在里面編寫(xiě)代碼。當(dāng)我們保存并關(guān)閉這個(gè)文件時(shí),IPython 就會(huì)自動(dòng)執(zhí)行該文件。
我通常將它與vim編輯器結(jié)合使用,這樣就不需要切換到代碼編輯器了,當(dāng)編寫(xiě)稍微長(zhǎng)一點(diǎn)的函數(shù)時(shí),效果很好。但是,如果函數(shù)體的代碼過(guò)多,那么直接在 IPython中編寫(xiě)就比較麻煩了。
4. 使用%edit -p打開(kāi)之前的文件
4_edit_p.gif
假如我們想修改上次編寫(xiě)的代碼,可以使用%edit -p重新打開(kāi)文件。
5. 通配符搜索
?
In?[1]:?import?os In?[2]:?os.*dir*? os.__dir__ os.chdir os.curdir os.fchdir os.listdir os.makedirs os.mkdir os.pardir os.removedirs os.rmdir os.scandir os.supports_dir_fd In?[3]:?os.chdir("/some/other/dir")
?
如果我們忘記了某個(gè)函數(shù)的名稱,可以使用動(dòng)態(tài)對(duì)象檢查(“?”)和通配符(“*”)進(jìn)行搜索。例如,我們知道os模塊有一個(gè)可以改變當(dāng)前目錄的方法,但是忘記了該方法的具體名稱。可以列出os模塊中的所有函數(shù),由于關(guān)于文件操作的函數(shù)名稱中包含“dir”。因此,可以搜索os模塊中名稱包含“dir”的所有函數(shù)。
6. %debug
假如程序出現(xiàn)了異常,我們可以使用%debug命令開(kāi)啟調(diào)試。無(wú)需打斷點(diǎn),或者使用特殊的參數(shù)運(yùn)行 IPython。
?
In?[1]:?from?solver?import?solve In?[2]:?solve() IndexError:?list?index?out?of?range In?[3]:?%debug >?/Users/switowski/workspace/iac/solver.py(11)count_trees() ??????9?????????x?=?(x?+?dx)?%?mod ?????10?????????y?+=?dy --->?11?????????if?values[y][x]?==?"#": ?????12?????????????count?+=?1 ?????13?????return?count ipdb>
?
7. 自動(dòng)開(kāi)啟調(diào)試
如果我們希望異常出現(xiàn)時(shí),調(diào)試器自動(dòng)啟動(dòng),可以使用%pdb命令,再次使用該命令會(huì)關(guān)閉該功能。
?
In?[1]:?%pdb Automatic?pdb?calling?has?been?turned?ON In?[2]:?from?solver?import?solve In?[3]:?solve() IndexError:?list?index?out?of?range >?/Users/switowski/workspace/iac/solver.py(11)count_trees() ??????9?????????x?=?(x?+?dx)?%?mod ?????10?????????y?+=?dy --->?11?????????if?values[y][x]?==?"#": ?????12?????????????count?+=?1 ?????13?????return?count ipdb>?y 1 ipdb>?x 3 ipdb>
?
8. shell命令
如果想在 IPython 中使用shell命令,可以在命令前加上感嘆號(hào)。像ls, pwd, cd這種常用shell命令,也可以不加感嘆號(hào)。我主要使用shell命令來(lái)移動(dòng)文件,或者在文件夾間移動(dòng)。我們還可以在Ipython中為另一種編程語(yǔ)言開(kāi)啟REPL。
?
In?[1]:?!pwd /Users/switowski/workspace/iac In?[2]:?ls?-al total?8 drwxr-xr-x???5?switowski??staff???480?Dec?21?17:26?./ drwxr-xr-x??55?switowski??staff??1760?Dec?22?14:47?../ drwxr-xr-x???9?switowski??staff???384?Dec?21?17:27?.git/ drwxr-xr-x???4?switowski??staff???160?Jan?25?11:39?__pycache__/ -rw-r--r--???1?switowski??staff???344?Dec?21?17:26?solver.py #?Node?REPL?inside?IPython??Sure! In?[3]:?!node Welcome?to?Node.js?v12.8.0. Type?".help"?for?more?information. >?var?x?=?"Hello?world" undefined >?x 'Hello?world' >
?
9. 使用%cd命令在文件系統(tǒng)間移動(dòng)
我們可以使用%cd命令在文件系統(tǒng)中移動(dòng)(按Tab鍵可以自動(dòng)補(bǔ)全文件夾路徑)。此外,還可以收藏一個(gè)文件夾或?qū)⒁恍┪募A移回歷史記錄(運(yùn)行%cd?查看該命令的具體信息)。
?
In?[1]:?!pwd /Users/switowski/workspace/iac/input_files/wrong/folder In?[2]:?%cd?../.. /Users/switowski/workspace/iac/input_files In?[3]:?%cd?right_folder/ /Users/switowski/workspace/iac/input_files/right_folder
?
10. %autoreload
使用%autoreload命令可以在運(yùn)行導(dǎo)入的函數(shù)前,重載該函數(shù)。當(dāng)我們?cè)?Python 中導(dǎo)入一個(gè)函數(shù)時(shí),Python 會(huì)將其源代碼保存在內(nèi)存中(實(shí)際上,真實(shí)的情況比較復(fù)雜)。當(dāng)我們更改了函數(shù),Python 不會(huì)重新加載函數(shù),而是繼續(xù)使用之前的代碼。
如果我們想創(chuàng)建一個(gè)函數(shù)或模塊,并且希望在不重啟 IPython 的情況下測(cè)試代碼(可以使用importlib.reload()),就可以使用%autoreload。通過(guò)使用該命令,就可以實(shí)現(xiàn)重載函數(shù)的效果。如果你想了解更多信息,可以查看這篇文章[1]。
10_autoreload.gif
11. 用%xmode展示詳細(xì)的異常信息
默認(rèn)情況下,IPython 拋出的異常信息量足夠查找錯(cuò)誤——至少對(duì)我來(lái)說(shuō)是這樣。但是,如果你想展示詳細(xì)的異常信息,可以使用%xmode命令。它可以用四種形式展示異常信息,開(kāi)發(fā)者按需選擇。
Minimal
?
In?[1]:?%xmode Exception?reporting?mode:?Minimal In?[2]:?solve() IndexError:?list?index?out?of?range?
?
Plain
?
In?[3]:?%xmode Exception?reporting?mode:?Plain In?[4]:?solve() Traceback?(most?recent?call?last): ??File?"",?line?1,?in? ????solve() ??File?"/Users/switowski/workspace/iac/solver.py",?line?27,?in?solve ????sol_part1?=?part1(vals) ??File?"/Users/switowski/workspace/iac/solver.py",?line?16,?in?part1 ????return?count_trees(vals,?3,?1) ??File?"/Users/switowski/workspace/iac/solver.py",?line?11,?in?count_trees ????if?vals[y][x]?==?"#": IndexError:?list?index?out?of?range
?
Context(默認(rèn)設(shè)置)
?
In?[5]:?%xmode Exception?reporting?mode:?Context In?[6]:?solve() --------------------------------------------------------------------------- IndexError????????????????????????????????Traceback?(most?recent?call?last) ?in? ---->?1?solve() ~/workspace/iac/solver.py?in?solve() ?????25?def?solve(): ?????26?????vals?=?getInput() --->?27?????sol_part1?=?part1(vals) ?????28?????print(f"Part?1:?{sol_part1}") ?????29?????print(f"Part?2:?{part2(vals,?sol_part1)}") ~/workspace/iac/solver.py?in?part1(vals) ?????14 ?????15?def?part1(vals:?list)?->?int: --->?16?????return?count_trees(vals,?3,?1) ?????17 ?????18?def?part2(vals:?list,?sol_part1:?int)?->?int: ~/workspace/iac/solver.py?in?count_trees(vals,?dx,?dy) ??????9?????????x?=?(x?+?dx)?%?mod ?????10?????????y?+=?dy --->?11?????????if?vals[y][x]?==?"#": ?????12?????????????cnt?+=?1 ?????13?????return?cnt IndexError:?list?index?out?of?range
?
Verbose (與context類似,但其中包含局部變量和全局變量)
?
In?[7]:?%xmode Exception?reporting?mode:?Verbose In?[8]:?solve() --------------------------------------------------------------------------- IndexError????????????????????????????????Traceback?(most?recent?call?last) ?in? ---->?1?solve() ????????global?solve?=? ~/workspace/iac/solver.py?in?solve() ?????25?def?solve(): ?????26?????values?=?read_input() --->?27?????part1?=?solve1(values) ????????part1?=?undefined ????????global?solve1?=? ????????values?=?[['..##.......',?...,?'.#..#...#.#']] ?????28?????print(f"Part?1:?{part1}") ?????29?????print(f"Part?2:?{solve2(values,?part1)}") ~/workspace/iac/solver.py?in?solve1(values=[['..##.......',?...,?'.#..#...#.#']]) ?????14 ?????15?def?solve1(values:?list)?->?int: --->?16?????return?count_trees(values,?3,?1) ????????global?count_trees?=? ????????values?=?[['..##.......',?...,?'.#..#...#.#']] ?????17 ?????18?def?solve2(values:?list,?sol_part1:?int)?->?int: ...?and?so?on IndexError:?list?index?out?of?range
?
12. ?rerun 命令
可以使用%rerun ~1/重新運(yùn)行前一個(gè)會(huì)話中的所有命令。但該命令有一個(gè)很大的缺點(diǎn)——如果之前的會(huì)話中有任何異常,執(zhí)行就會(huì)停止。因此,必須手動(dòng)刪除有異常的命令行。如果你正在使用Jupyter notebook,可以將出現(xiàn)異常的地方標(biāo)記為“raising an exception”。如果使用rerun 命令,IPython 將忽略此異常。這不是一個(gè)完美的解決方案,假如可以在%rerun命令設(shè)置,效果會(huì)更好。
?
In?[1]:?a?=?10 In?[2]:?b?=?a?+?20 In?[3]:?b Out[3]:?30 #?Restart?IPython In?[1]:?%rerun?~1/ ===?Executing:?=== a?=?10 b?=?a?+?20 b ===?Output:?=== Out[1]:?30 In?[2]:?b Out[2]:?30
?
13. 在啟動(dòng) IPython 時(shí)運(yùn)行某些代碼
如果你想在每次啟動(dòng) IPython 時(shí)執(zhí)行一些代碼,只需在“startup”文件夾(~/.Ipython /profile_default/startup/)中創(chuàng)建一個(gè)新文件,并在其中書(shū)寫(xiě)代碼。IPython將自動(dòng)執(zhí)行該文件。你也可以在該文件中導(dǎo)入一些模塊,但如果文件中的代碼過(guò)多,將會(huì)影響IPython的啟動(dòng)速度。
13_startup.gif
14. 使用不同的配置文件
如果我們想導(dǎo)入一些模塊,并配置某些東西。例如在調(diào)試/分析時(shí),我們想讓輸出的異常信息為verbose模式,并導(dǎo)入一些分析庫(kù)。此時(shí)不能將其放入默認(rèn)配置文件中,因?yàn)槲覀儫o(wú)需對(duì)每個(gè)文件都進(jìn)行調(diào)試或分析。我們可以創(chuàng)建一個(gè)新的配置文件。配置文件就像IPython的不同用戶帳戶——每個(gè)帳戶都有自己的配置文件和啟動(dòng)文件夾。
14_profile.gif
15. ?保存表達(dá)式結(jié)果
如果你忘記了將表達(dá)式賦值給變量,可以使用var = _. _存儲(chǔ)最后一個(gè)命令的輸出(這在Python REPL中也適用)。這樣前面所有命令的結(jié)果都存儲(chǔ)在了:變量_1(第一個(gè)命令的輸出),_2(第二個(gè)命令的輸出),依次類推。
?
In?[1]:?sum(range(1000000)) Out[1]:?499999500000 In?[2]:?the_sum?=?_ In?[3]:?the_sum Out[3]:?499999500000 In?[4]:?_1 Out[4]:?499999500000
?
16. 編輯任何函數(shù)或模塊
你可以使用%edit編輯任何Python函數(shù),包括:自定義的函數(shù),用pip安裝的第三方庫(kù)中的函數(shù),甚至是內(nèi)置的函數(shù)。甚至不需要知道函數(shù)位于哪個(gè)文件中,只需指定函數(shù)名稱(必須先導(dǎo)入它),IPython 就會(huì)自動(dòng)找到它。在下面的例子中,我修改了內(nèi)置的randint()函數(shù),讓它始終返回42。
16_edit.gif
17. 分享代碼
如果你想把代碼分享給其他人,可以使用%pastebin命令,并指定共享的代碼。IPython 將創(chuàng)建一個(gè)pastebin(類似于GitHub 的 gist),粘貼選定的行,并返回一個(gè)鏈接,你可以把它發(fā)送給別人。務(wù)必記住,這個(gè)鏈接會(huì)在7天后過(guò)期。
?
In?[1]:?welcome?=?"Welcome?to?my?gist" In?[2]:?welcome Out[2]:?'Welcome?to?my?gist' In?[3]:?a?=?42 In?[4]:?b?=?41 In?[5]:?a?-?b Out[5]:?1 In?[6]:?%pastebin?1-5 Out[6]:?'http://dpaste.com/8QA86F776'
?
18. 將 IPython 作為debugger
我們還可以把 IPython 當(dāng)作debugger使用。IPython自帶“ipdb”——它類似于內(nèi)置的Python調(diào)試器“pdb”,但其中有一些IPython的特有特性(語(yǔ)法高亮顯示、自動(dòng)補(bǔ)全等)。通過(guò)設(shè)置PYTHONBREAKPOINT環(huán)境變量,調(diào)用breakpoint(),就可以在斷點(diǎn)語(yǔ)句中使用ipdb了。但需要在 Python 3.7或更高版本中使用(Python3.7之后才引入了breakpoint()語(yǔ)句)。18_debugger.gif
19. 執(zhí)行用其他語(yǔ)言編寫(xiě)的代碼
假設(shè)我們想要在不退出 IPython 的情況下,執(zhí)行用另一種語(yǔ)言編寫(xiě)的一些代碼。比如輸入%%ruby,再編寫(xiě)一些Ruby代碼,然后按兩次Enter鍵,IPython就會(huì)運(yùn)行這段代碼。IPython 支持Ruby、Bash或JavaScript等語(yǔ)言。它也適用于Python2 (%%python2)。
?
In?[1]:?%%ruby ???...:?1.upto?16?do?|i| ???...:???out?=?"" ???...:???out?+=?"Fizz"?if?i?%?3?==?0 ???...:???out?+=?"Buzz"?if?i?%?5?==?0 ???...:???puts?out.empty????i?:?out ???...:?end ???...: ???...: 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16
?
20. 在會(huì)話中存儲(chǔ)變量
IPython使用SQLite來(lái)存儲(chǔ)之前的會(huì)話。我們也可以用它來(lái)存儲(chǔ)自定義的數(shù)據(jù)。例如,使用%store命令,就可以在IPython的數(shù)據(jù)庫(kù)中保存變量,使用estore -r可以另一個(gè)會(huì)話中恢復(fù)它們。您還可以在配置文件中設(shè)置c.StoreMagics.autorestore = True,以便在啟動(dòng)IPython時(shí)自動(dòng)從數(shù)據(jù)庫(kù)恢復(fù)所有變量。
?
In?[1]:?a?=?100 In?[2]:?%store?a Stored?'a'?(int) #?Restart?IPython In?[1]:?%store?-r?a In?[2]:?a Out[2]:?100
?
21. 將會(huì)話保存進(jìn)一個(gè)文件
我們可以使用%save命令將IPython會(huì)話保存到一個(gè)文件中,然后對(duì)代碼進(jìn)行修改,無(wú)需手動(dòng)復(fù)制粘貼到代碼編輯器中。
?
In?[1]:?a?=?100 In?[2]:?b?=?200 In?[3]:?c?=?a?+?b In?[4]:?c Out[4]:?300 In?[5]:?%save?filename.py?1-4 The?following?commands?were?written?to?file?`filename.py`: a?=?100 b?=?200 c?=?a?+?b c
?
22. 清理>標(biāo)記或者不正確的縮進(jìn)
如果我們想清除不正確的縮進(jìn)或“>”符號(hào)(例如,從git diff、文檔字符串或電子郵件中復(fù)制的代碼,都含有冗余信息),無(wú)需手動(dòng)操作,可以復(fù)制代碼并運(yùn)行%paste。IPython將從剪貼板粘貼代碼,修復(fù)縮進(jìn),并刪除“>”符號(hào)(盡管它有時(shí)不能正常工作)。
?
#?Clipboard?content: #?>def?greet(name): #?>????print(f"Hello?{name}") #?Just?pasting?the?code?won't?work In?[1]:?>def?greet(name): ???...:?>????print(f"Hello?{name}") ??File?"",?line?1 ????>def?greet(name): ????^ SyntaxError:?invalid?syntax #?But?using?%paste?works In?[2]:?%paste >def?greet(name): >????print(f"Hello?{name}") ##?--?End?pasted?text?-- In?[3]:?greet("Sebastian") Hello?Sebastian
?
23. 列出所有變量
使用%whos命令可以顯示出當(dāng)前會(huì)話的所有變量,包括變量類型和存儲(chǔ)的數(shù)據(jù)。
?
In?[1]:?a?=?100 In?[2]:?name?=?"Sebastian" In?[3]:?squares?=?[x*x?for?x?in?range(100)] In?[4]:?squares_sum?=?sum(squares) In?[5]:?def?say_hello(): ???...:?????print("Hello!") ???...: In?[6]:?%whos Variable??????Type????????Data/Info ----------------------------------- a?????????????int?????????100 name??????????str?????????Sebastian say_hello?????function???? squares???????list????????n=100 squares_sum???int?????????328350
?
24. 使用異步函數(shù)
可以使用異步函數(shù)提高代碼的運(yùn)行速度。要使用異步,必須先啟動(dòng)一個(gè)事件循環(huán)來(lái)調(diào)用它們。方便的是,IPython自帶事件循環(huán)!這樣,無(wú)需額外操作就能使用異步函數(shù)了。
?
In?[1]:?import?asyncio In?[2]:?async?def?worker(): ???...:?????print("Hi") ???...:?????await?asyncio.sleep(2) ???...:?????print("Bye") ???...: #?The?following?code?would?fail?in?the?standard?Python?REPL #?because?we?can't?call?await?outside?of?an?async?function In?[3]:?await?asyncio.gather(worker(),?worker(),?worker()) Hi Hi Hi Bye Bye Bye
?
25. IPython 腳本
我們可以在命令前加上!或者&,執(zhí)行包含 IPython 特定語(yǔ)法的文件,這種文件的擴(kuò)展名為“ipy”。
?
$?ls file1.py????file2.py????file3.py????file4.py????wishes.ipy $?cat?wishes.ipy files?=?!ls #?suffix?運(yùn)行所有后綴為.py的文件 for?file?in?files: ????if?file.endswith(".py"): ????????%run?$file $?ipython?wishes.ipy Have?a Very?Merry Christmas!
?
結(jié)論
IPython 是我最喜歡的 Python 工具之一。它有許多好用的特性,本文分享了一些,如果你知道其他特性,可以留言分享!
審核編輯:湯梓紅
?
評(píng)論
查看更多