交互式解释器为什么叫 REPL
今天着重介绍 Python 解释器的交互式模式。
什么是 REPL
REPL 是 4 个单词的首字母组:Read Eval Print Loop.
它表示一个循环中,在这个循环中不断的执行:
Read -> Eval -> Print -> Read -> Eval
-> Print -> Read -> Eval -> Print -> ...
所以更准确点的英文写法其实是 2 个单词: read-eval-print loop
。
![REPL wiki](images/REPL wiki.png)
- Read,读取用户输入
- Eval, 执行输入内容
- Print,打印输出结果
- Loop, 不断循环以上步骤
由上面的描述可知,我们经常用的命令行或 Shell 就是这种模式。不过一般提起 REPL 的时候,都是特指编程语言的交互式运行环境。
拥有交互式的编程环境对一个语言来说,特别是它的学习者来说,是一个非常大的帮助。
下面我们就重点聊聊 Python 的 REPL。
进入 Loop
大概有这么几种方式能够进入 python 的交互式解释器模式:
- 不带任何参数运行
python
,这是最常见的方式 - 通过
py
启动器运行解释器,这是 windows 下特有的方式 - 使用
python -i some_script.py
,执行脚本后再进入,这个我们也在前面文章中介绍过了 - 其它 IDE(IDLE, PyCharm 等)内嵌的所谓
python shell
或python console
,它们也要依赖系统安装的python
进入之后,首先看到的就是一段开场信息,然后就是 >>>
和一个闪烁的光标在等待你的输入。
冷门小知识:启动时打印的消息称为
banner
,想要自定义它? 得从源码编译 python。不过如果是嵌套实现,可以参考标准库code
模块。事实上,一般 IDE 中内嵌的 Shell 多半都是在code
模块之上封装的。
前面的符号 >>>
称为 提示符(Prompt String),我们在命令行中看到的 >
或 $
或 #
等都是提示符。
熟悉 Linux 系统的小伙伴可能知道,环境变量有一个 PS1
,可以用来定义提示符的样式:
[root@host ~]# echo $PS1
[\u@\h \W]\$
这里的 1
代表序号,表示这是主提示符,后面还有 PS2
,PS3
,PS4
。
扯远了,咱还是回到 python。同样的,这里的 >>>
也是主提示符,它是保存在 sys.ps1
这个特殊变量里的,此外还有个 sys.ps2
的值是 ...
。
注意,提示符后面有 1 个空格。
sys.ps1 = '>>> '
,sys.ps2 = '... '
。
好玩的是,这两个变量是可以自定义的:
>>> sys.ps1 = 'DavyCloud Python 教程 2020 > '
DavyCloud Python 教程 2020 >
DavyCloud Python 教程 2020 > x = 1
DavyCloud Python 教程 2020 > print(x)
1
2
号提示符啥时候出场,继续看下面。
READ
一般情况下,按下回车键,就表示输入完毕,解释器就读取刚才输入的整个语句,开始执行了。大多数情况下,这些都是一行搞定。
如果从 Python 语法上讲,当前行没有结束,则还会继续等待输入,此时显示的就是 2 号提示符 ...
,用户可以继续输入。
具体有以下几种情况:
复合语句块
例如:
def
class
if
/for
/while
try
/except
with
因为 python 不像其它语言那样用括号表示代码块的开始和结束,所以这种情况下,解释器无法判断何时代码块会结束。即使像下面这样挤在一行写也没用:
>>> x = 1
>>> if x == 1:pass
...
>>>
>>> def func(): return 1
...
>>>
开放的括号
例如:
>>> (1,
... 3,
... 4)
(1, 3, 4)
>>> {"name":
... 123, "key"
... :234}
{'name': 123, 'key': 234}
开放的三引号
普通的字符串是不行的,三引号的字符串则可以:
>>> "hello
File "<stdin>", line 1
"hello
^
SyntaxError: EOL while scanning string literal
>>> """hello
... xxx
... """
'hello\nxxx\n'
>>>
使用反斜杠 \
结尾
在回车之前输入一个反斜杠 \
,就能只换行而不完成输入,这招写代码的时候也一样适用。
值得注意的是,反斜杠 \
之后不能再有任何字符,包括空格。否则都是语法错误。
Eval
Eval
是 Evaluate
的简写。这一步就是解释器执行它读到的代码。
注意,python 里有 1 个内置函数 eval
,它和这里的 Eval
可不完全一样。eval
只能执行 表达式(Expression),而这里解释器可以接受任何语句。从这一点看,解释器的 Eval
行为和内置的 exec
更贴近。
有一点需要特别提醒的是,如果输入的代码是一个表达式,那么交互式模式下,会把这个表达式的值存在一个特殊变量中,变量名是: _
(一个下划线)
Print
python 交互解释器的 Print
和内置函数 print
有一点细微差别:
当我们调用 print()
函数的时候,打印到屏幕上(即 stdout
)的内容是 print()
函数写入的。print()
函数本身是没有任何结果返回的。
python 交互式解释器的 Print
只打印表达式的结果。所以呢,如果我们是在交互模式下输出 helloworld 是不需要调用 print()
函数的:
>>> "helloworld"
'helloworld'
细心的小伙伴会发现,这种方式打印出来的结果是带了引号的。
Tips:可以看到我们用的是双引号,而打印出来是单引号,可见 python 是优先使用 单引号表示字符串的。
这是因为在 python 里对象有 2 种生成文本表示的方法,1 个大家比较熟悉,是 str()
,另一个则相对比较陌生了,是 repr()
。
print()
方法对应的是 str
,即 print(obj)
等价于 print(str(obj))
。而 REPL
中的 Print
对应的是 repr
,即等价于 print(repr(obj))
。
写个简单的小例子体会下:
>>> print(repr("helloworld"))
'helloworld'
# 下面更复杂点的例子
>>> class C:
def __repr__(self):
return 'repr'
def __str__(self):
return 'str'
>>> c = C()
>>> c
repr
>>> print(c)
str
>>>
关于
str
和repr
的细微差别,有机会可以再细聊。
除了字符串,还有其它各种对象都可以自动打印,所以在交互模式下看一个对象是什么非常方便。
在前面的示例中也给大家介绍了,我最常用的就是显示模块信息,来获取模块所在路径信息。
退出 Loop
在命令行中我们常用的退出命令是 exit
或 quit
,在 python 中输入它们会提示:
>>> quit
Use quit() or Ctrl-Z plus Return to exit
>>> exit
Use exit() or Ctrl-Z plus Return to exit
因为 python 接受的不是命令,只能接受函数,所以必需要带括号。同时还提示我们可以用快捷键 Ctrl-Z
退出。
这个快捷键是 Windows
系统下的,如果是 Linux
系统就应该是 Ctrl-D
了:
>>> quit
Use quit() or Ctrl-D (i.e. EOF) to exit
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
>>>
Ctrl-D
在 Linux
系统中代表着 EOF(End Of File)
的含义,很多命令都支持这个快捷键结束。而 Ctrl-Z
在 Linux
系统中是把任务挂入后台,实际并不会退出。
小提示,如果
Ctrl-Z
把进程挂到后台后,执行fg
命令可恢复。fg(fore ground)
就是前台的意思。
另外值得提醒的是,exit()
和 quit()
都支持传入一个整数作为程序的返回码,0
表示正常结束,非 0
值表示异常结束。
一道思考题:
在 python 解释器中执行
exit
的时候出现的提示需要带括号这种信息,这是如何做到的?
增强型 REPL
python 解释器的交互模式虽然很方便了,但是还有所不足。
在 Linux
系统的 shell
中,有很多非常方便的命令,一旦进入了 python shell
,这些命令就都不能用了,特别是一些比较常用的比如 pwd
显示当前路径,ls
显示文件列表等。
虽然这些可以通过调用标准库提供的方法实现,但是没有直接命令来的方便。
如果说不能访问系统的 shell
命令这个不足有点牵强,那么缺少语法高亮,智能提示,自动补全等就显得比较难以接受了。
还有,虽然刚才我们提到了 _
可以自动保存表达式的值,但是它只能保存最近依一次的。前面执行过的结果如果忘了存变量,就只能再来一次了。
优秀的程序员都是懒人,这些都不能忍!所以除了 python 官方自带的解释器,有很多第三方的增强型解释器出现,这里面最成功的就是 IPython。
自带解释器上面提的所以不足之处,IPython
统统解决,并且做的更出色。
不仅如此,
IPython
最终还进化成了一个跨语言的Jyputer
项目。已经成为 python 在科学计算领域必不可少的工具了。
小结
介绍 REPL 的概念,以及 Python 解释器的交互式模式有哪些需要注意的地方。
文章内容虽基础,整理发布不轻松
如果看过有帮助,不妨 点赞 + 关注,谢谢!