MicroPython 交互式解释器模式(又名 REPL)

本节介绍 MicroPython 交互式解释器模式的一些特性。一个常用的术语是 REPL (read-eval-print-loop),它将用来指代这个交互式提示。

自动缩进

当输入以冒号结尾的 python 语句时(例如 if、for、while),提示将变为三个点 (...),光标将缩进 4 个空格。当您按下回车键时,下一行将继续使用与常规语句相同的缩进级别或适当的额外缩进级别。如果您按退格键,则会撤消一级缩进。

如果您的光标一直回到开头,按 RETURN 将执行您输入的代码。下面显示了您在输入 for 语句后会看到的内容(下划线显示光标所在的位置):

>>> for i in range(30):
...     _

如果您随后输入 if 语句,则会提供额外的缩进级别:

>>> for i in range(30):
...     if i > 3:
...         _

现在输入break后跟 RETURN 并按 BACKSPACE:

>>> for i in range(30):
...     if i > 3:
...         break
...     _

最后输入 print(i)最后输入:

>>> for i in range(30):
...     if i > 3:
...         break
...     print(i)
...
0
1
2
3
>>>

如果前两行都是空格,则不会应用自动缩进。这意味着您可以通过按两次 RETURN 来完成输入复合语句,然后第三次按将完成并执行。

自动完成

在 REPL 中键入命令时,如果到目前为止键入的行对应于某些名称的开头,则按 TAB 将显示可以输入的可能内容。例如,首先通过输入并按 RETURN 来导入机器模块。然后键入并按 TAB,它应该扩展为. 输入一个点,然后再次按 TAB。你应该看到类似的东西: import machine m machine

>>> machine.
__name__        info            unique_id       reset
bootloader      freq            rng             idle
sleep           deepsleep       disable_irq     enable_irq
Pin

这个词将尽可能地扩展,直到存在多种可能性。例如,键入machine.Pin.AF3并按 TAB 键,它将扩展为 machine.Pin.AF3_TIM. 再次按 TAB 将显示可能的扩展:

>>> machine.Pin.AF3_TIM
AF3_TIM10       AF3_TIM11       AF3_TIM8        AF3_TIM9
>>> machine.Pin.AF3_TIM

中断正在运行的程序

您可以通过按 Ctrl-C 来中断正在运行的程序。这将引发一个 KeyboardInterrupt,它将带你回到 REPL,前提是你的程序不拦截 KeyboardInterrupt 异常。

例如:

>>> for i in range(1000000):
...     print(i)
...
0
1
2
3
...
6466
6467
6468
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
KeyboardInterrupt:
>>>

粘贴模式

如果您想将一些代码粘贴到终端窗口中,自动缩进功能会将事情搞砸。例如,如果您有以下 Python 代码:

def foo():
    print('This is a test to show paste mode')
    print('Here is a second line')
foo()

并且您尝试将其粘贴到普通 REPL 中,然后您将看到如下内容:

>>> def foo():
...         print('This is a test to show paste mode')
...             print('Here is a second line')
...             foo()
...
  File "<stdin>", line 3
IndentationError: unexpected indent

如果您按 Ctrl-E,那么您将进入粘贴模式,这实际上会关闭自动缩进功能,并将提示从 更改>>>===。例如:

>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== def foo():
===     print('This is a test to show paste mode')
===     print('Here is a second line')
=== foo()
===
This is a test to show paste mode
Here is a second line
>>>

粘贴模式允许粘贴空白行。粘贴的文本像文件一样被编译。按 Ctrl-D 退出粘贴模式并启动编译。

软复位

软重置将重置 python 解释器,但不会尝试重置您连接到 MicroPython 板(USB 串行或 Wifi)的方法。

您可以通过按 Ctrl-D 从 REPL 执行软重置,或者通过执行以下命令从您的 Python 代码执行:

machine.soft_reset()

例如,如果您重置 MicroPython 板并执行 dir() 命令,您会看到如下内容:

>>> dir()
['__name__', 'pyb']

现在创建一些变量并重复 dir() 命令:

>>> i = 1
>>> j = 23
>>> x = 'abc'
>>> dir()
['j', 'x', '__name__', 'pyb', 'i']
>>>

现在,如果您输入 Ctrl-D,并重复 dir() 命令,您将看到您的变量不再存在:

MPY: sync filesystems
MPY: soft reboot
MicroPython v1.5-51-g6f70283-dirty on 2015-10-30; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> dir()
['__name__', 'pyb']
>>>

特殊变量 _(下划线)

当您使用 REPL 时,您可以执行计算并查看结果。MicroPython 将上一条语句的结果存储在变量 _(下划线)中。因此,您可以使用下划线将结果保存在变量中。例如:

>>> 1 + 2 + 3 + 4 + 5
15
>>> x = _
>>> x
15
>>>

原始模式和原始粘贴模式

原始模式(也称为原始 REPL)不是人们通常会使用的。它旨在用于编程用途,本质上类似于粘贴模式,关闭回声,并具有可选的流量控制。

使用 Ctrl-A 进入原始模式。然后发送你的python代码,然后是Ctrl-D。Ctrl-D 将通过“OK”确认,然后将编译和执行 python 代码。任何输出(或错误)都将被发回。输入 Ctrl-B 将退出原始模式并返回常规(又名友好)REPL。

原始粘贴模式是原始 REPL 中的一种附加模式,它包括流控制,并在收到代码时对其进行编译。这使得它在将代码高速传输到设备时更加健壮,并且在接收时也使用更少的 RAM,因为它不需要在编译前存储代码的逐字副本(与标准原始模式不同)。

原始粘贴模式使用以下协议:

  1. 像往常一样通过 ctrl-A 输入原始 REPL。

  2. 写入 3 个字节:(b"\x05A\x01" 即 ctrl-E 然后“A”然后 ctrl-A)。

  3. 读取 2 个字节以确定设备是否进入原始粘贴模式:

    • 如果结果是, b"R\x00" 则设备理解命令但不支持原始粘贴。

    • 如果结果是,b"R\x01" 则设备确实支持原始粘贴并已进入此模式。

    • 否则结果应该是 b"ra"并且设备不支持原始粘贴并且应该读取并丢弃该字符串。b"w REPL; CTRL-B to exit\r\n>"

  4. 如果设备处于原始粘贴模式,则继续,否则回退到标准原始模式。

  5. 读取 2 个字节,这是存储为 16 位无符号小端整数的流控制窗口大小增量(以字节为单位)。剩余窗口大小变量的初始值应设置为此数字。

  6. 将代码写入设备:

    • 当有字节要发送时,写入剩余窗口大小的字节数,并将剩余窗口大小减少写入的字节数。

    • 如果剩余窗口大小为 0,或者有一个字节等待读取,则读取 1 个字节。如果此字节b"\x01" 然后由窗口大小增量从步骤5增加剩余的窗口大小如果该字节是 b"\x04" ,则设备想要结束数据接收,和 b"\x04" 应写入设备并没有更多的代码发送后那。(注意:如果有一个字节等待从设备读取,那么它不需要立即读取和操作,只要 reaming-window-size 大于 0,设备将继续消耗传入的字节。)

  7. 将所有代码写入设备后,写入b"\x04"以指示数据结束。

  8. 从设备读取直到b"\x04"收到。此时,设备已经接收并编译了所有发送并正在执行的代码。

  9. 设备输出由执行代码产生的任何字符。当 (if) 代码完成时 b"\x04"将输出,然后是任何未捕获的异常,然后是 b"\x04". 然后它返回到标准的原始 REPL 和输出 b">"

例如,在正常的(友好的)REPL 处从一个新行开始,如果你写:

b"\x01\x05A\x01print(123)\x04"

然后设备将响应如下:

b"\r\nraw REPL; CTRL-B to exit\r\n>R\x01\x80\x00\x01\x04123\r\n\x04\x04>"

随着时间的推移分解如下:

# Step 1: enter raw REPL
write: b"\x01"
read: b"\r\nraw REPL; CTRL-B to exit\r\n>"

# Step 2-5: enter raw-paste mode
write: b"\x05A\x01"
read: b"R\x01\x80\x00\x01"

# Step 6-8: write out code
write: b"print(123)\x04"
read: b"\x04"

# Step 9: code executes and result is read
read: b"123\r\n\x04\x04>"

在这种情况下,流控制窗口大小增量为 128,并且在开始时有两个窗口值立即可用的数据,一个来自初始窗口大小增量值,另一个来自 b"\x01"发送的显式值。所以这意味着在等待或检查更多传入的流控制字符之前,最多可以写入 256 个字节。

tools/pyboard.py程序使用原始 REPL,包括原始粘贴模式,在启用 MicroPython 的板上执行 Python 代码。