【导语】:IPython 是一个 Python的交互式shell,比默认的 Python shell好用得多。它有许多好用的特性,本文将对一些特性进行介绍。
介绍
IPython 是一个Python的交互式shell,比默认的 Python shell好用得多,支持变量自动补全,自动缩进,内置了许多很有用的功能和函数。在之前的项目中,我使用 IPython 较多,每当在开发中遇到问题时,我会打印每一步的输出,查找问题。完成项目后,我对之前使用 IPython 的一些经验作了总结。在本文,我将对之前的总结作以简单介绍。
此外,文中的部分命令配有 gif 图演示,但由于比较大,没法上传到微信公众号。如果有需要 gif 演示动图的小伙伴,请看文末获取方式。
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
?
这是我最喜欢的功能之一。我们可以通过在任何函数、模块、变量的开头或结尾添加“?”来显示其文档。它被称为“动态对象检查”,通过使用该特性,我们就可以在不退出终端的情况下来获取文档。在标准的Python交互式解释器中REPL中,使用help()函数也能获取文档信息,但"?"输出的文档可读性更强。它能将函数签名对象signature、文档字符串等重要信息高亮显示。(由于我使用的语法高亮库不支持Ipython,因此在这里无法显示)
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 ????----------
?
假如我们想查看一个函数(或者类/模块)的源代码,可以使用两个问号,例如:function_name??,??function_name。
3. %edit 函数
3_edit.gif
如果我们想在 IPython 中写一个功能较复杂的函数,可以使用 %edit 命令打开自己喜欢的编辑器(也可以用 $editor环境变量设置编辑器),在里面编写代码。当我们保存并关闭这个文件时,IPython 就会自动执行该文件。
我通常将它与vim编辑器结合使用,这样就不需要切换到代码编辑器了,当编写稍微长一点的函数时,效果很好。但是,如果函数体的代码过多,那么直接在 IPython中编写就比较麻烦了。
4. 使用%edit -p打开之前的文件
4_edit_p.gif
假如我们想修改上次编写的代码,可以使用%edit -p重新打开文件。
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")
?
如果我们忘记了某个函数的名称,可以使用动态对象检查(“?”)和通配符(“*”)进行搜索。例如,我们知道os模块有一个可以改变当前目录的方法,但是忘记了该方法的具体名称。可以列出os模块中的所有函数,由于关于文件操作的函数名称中包含“dir”。因此,可以搜索os模块中名称包含“dir”的所有函数。
6. %debug
假如程序出现了异常,我们可以使用%debug命令开启调试。无需打断点,或者使用特殊的参数运行 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. 自动开启调试
如果我们希望异常出现时,调试器自动启动,可以使用%pdb命令,再次使用该命令会关闭该功能。
?
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命令,可以在命令前加上感叹号。像ls, pwd, cd这种常用shell命令,也可以不加感叹号。我主要使用shell命令来移动文件,或者在文件夹间移动。我们还可以在Ipython中为另一种编程语言开启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命令在文件系统间移动
我们可以使用%cd命令在文件系统中移动(按Tab键可以自动补全文件夹路径)。此外,还可以收藏一个文件夹或将一些文件夹移回历史记录(运行%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命令可以在运行导入的函数前,重载该函数。当我们在 Python 中导入一个函数时,Python 会将其源代码保存在内存中(实际上,真实的情况比较复杂)。当我们更改了函数,Python 不会重新加载函数,而是继续使用之前的代码。
如果我们想创建一个函数或模块,并且希望在不重启 IPython 的情况下测试代码(可以使用importlib.reload()),就可以使用%autoreload。通过使用该命令,就可以实现重载函数的效果。如果你想了解更多信息,可以查看这篇文章[1]。
10_autoreload.gif
11. 用%xmode展示详细的异常信息
默认情况下,IPython 抛出的异常信息量足够查找错误——至少对我来说是这样。但是,如果你想展示详细的异常信息,可以使用%xmode命令。它可以用四种形式展示异常信息,开发者按需选择。
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(默认设置)
?
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/重新运行前一个会话中的所有命令。但该命令有一个很大的缺点——如果之前的会话中有任何异常,执行就会停止。因此,必须手动删除有异常的命令行。如果你正在使用Jupyter notebook,可以将出现异常的地方标记为“raising an exception”。如果使用rerun 命令,IPython 将忽略此异常。这不是一个完美的解决方案,假如可以在%rerun命令设置,效果会更好。
?
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. 在启动 IPython 时运行某些代码
如果你想在每次启动 IPython 时执行一些代码,只需在“startup”文件夹(~/.Ipython /profile_default/startup/)中创建一个新文件,并在其中书写代码。IPython将自动执行该文件。你也可以在该文件中导入一些模块,但如果文件中的代码过多,将会影响IPython的启动速度。
13_startup.gif
14. 使用不同的配置文件
如果我们想导入一些模块,并配置某些东西。例如在调试/分析时,我们想让输出的异常信息为verbose模式,并导入一些分析库。此时不能将其放入默认配置文件中,因为我们无需对每个文件都进行调试或分析。我们可以创建一个新的配置文件。配置文件就像IPython的不同用户帐户——每个帐户都有自己的配置文件和启动文件夹。
14_profile.gif
15. ?保存表达式结果
如果你忘记了将表达式赋值给变量,可以使用var = _. _存储最后一个命令的输出(这在Python REPL中也适用)。这样前面所有命令的结果都存储在了:变量_1(第一个命令的输出),_2(第二个命令的输出),依次类推。
?
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. 编辑任何函数或模块
你可以使用%edit编辑任何Python函数,包括:自定义的函数,用pip安装的第三方库中的函数,甚至是内置的函数。甚至不需要知道函数位于哪个文件中,只需指定函数名称(必须先导入它),IPython 就会自动找到它。在下面的例子中,我修改了内置的randint()函数,让它始终返回42。
16_edit.gif
17. 分享代码
如果你想把代码分享给其他人,可以使用%pastebin命令,并指定共享的代码。IPython 将创建一个pastebin(类似于GitHub 的 gist),粘贴选定的行,并返回一个链接,你可以把它发送给别人。务必记住,这个链接会在7天后过期。
?
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 当作debugger使用。IPython自带“ipdb”——它类似于内置的Python调试器“pdb”,但其中有一些IPython的特有特性(语法高亮显示、自动补全等)。通过设置PYTHONBREAKPOINT环境变量,调用breakpoint(),就可以在断点语句中使用ipdb了。但需要在 Python 3.7或更高版本中使用(Python3.7之后才引入了breakpoint()语句)。18_debugger.gif
19. 执行用其他语言编写的代码
假设我们想要在不退出 IPython 的情况下,执行用另一种语言编写的一些代码。比如输入%%ruby,再编写一些Ruby代码,然后按两次Enter键,IPython就会运行这段代码。IPython 支持Ruby、Bash或JavaScript等语言。它也适用于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. 在会话中存储变量
IPython使用SQLite来存储之前的会话。我们也可以用它来存储自定义的数据。例如,使用%store命令,就可以在IPython的数据库中保存变量,使用estore -r可以另一个会话中恢复它们。您还可以在配置文件中设置c.StoreMagics.autorestore = True,以便在启动IPython时自动从数据库恢复所有变量。
?
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. 将会话保存进一个文件
我们可以使用%save命令将IPython会话保存到一个文件中,然后对代码进行修改,无需手动复制粘贴到代码编辑器中。
?
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. 清理>标记或者不正确的缩进
如果我们想清除不正确的缩进或“>”符号(例如,从git diff、文档字符串或电子邮件中复制的代码,都含有冗余信息),无需手动操作,可以复制代码并运行%paste。IPython将从剪贴板粘贴代码,修复缩进,并删除“>”符号(尽管它有时不能正常工作)。
?
#?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命令可以显示出当前会话的所有变量,包括变量类型和存储的数据。
?
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. 使用异步函数
可以使用异步函数提高代码的运行速度。要使用异步,必须先启动一个事件循环来调用它们。方便的是,IPython自带事件循环!这样,无需额外操作就能使用异步函数了。
?
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 脚本
我们可以在命令前加上!或者&,执行包含 IPython 特定语法的文件,这种文件的扩展名为“ipy”。
?
$?ls file1.py????file2.py????file3.py????file4.py????wishes.ipy $?cat?wishes.ipy files?=?!ls #?suffix?运行所有后缀为.py的文件 for?file?in?files: ????if?file.endswith(".py"): ????????%run?$file $?ipython?wishes.ipy Have?a Very?Merry Christmas!
?
结论
IPython 是我最喜欢的 Python 工具之一。它有许多好用的特性,本文分享了一些,如果你知道其他特性,可以留言分享!
审核编辑:汤梓红
?
评论