MicroPython 互動式直譯器模式(即 REPL)¶
本節介紹 MicroPython 互動式直譯器模式的一些特性。常用的術語是 REPL(read-eval-print-loop,讀取─求值─輸出迴圈),以下將以此來稱呼這個互動式提示字元。
備註
OpenMV Cam 透過其 USB 序列(CDC)連接埠提供此 REPL。它僅在你使用序列終端機模擬器(或諸如 MicroPython 遠端控制:mpremote 之類的工具)直接連接相機時才有意義。OpenMV IDE 並不使用 REPL — 它透過獨立的除錯通訊協定與相機溝通,以執行指令碼、傳輸檔案以及串流影格緩衝區。本頁所述的所有內容僅適用於直接的終端機工作階段。
自動縮排¶
當你輸入以冒號結尾的 Python 陳述式(例如 if、for、while)時,提示字元會變成三個點(...),並且游標會縮排 4 個空格。當你按下 Enter 鍵時,對於一般陳述式,下一行會以相同的縮排層級繼續;在適當的情況下則會增加一個縮排層級。如果你按下退格鍵,就會復原一個縮排層級。
如果你的游標已經回到最開頭的位置,按下 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),按下 RETURN,按下 BACKSPACE,再按一次 RETURN:
>>> for i in range(30):
... if i > 3:
... break
... print(i)
...
0
1
2
3
>>>
如果前兩行都是空格,就不會套用自動縮排。這表示你可以按兩次 RETURN 來完成輸入一個複合陳述式,然後第三次按下就會結束並執行。
自動補全¶
在 REPL 中輸入命令時,如果目前所輸入的內容對應到某個名稱的開頭,那麼按下 TAB 就會顯示可能要輸入的項目。例如,先輸入 import machine 並按下 RETURN 來匯入 machine 模組。接著輸入 m 並按下 TAB,它應該會展開為 machine。輸入一個句點 . 並再次按下 TAB。你應該會看到類似這樣的內容:
>>> machine.
__name__ info unique_id reset
bootloader freq rng idle
sleep deepsleep disable_irq enable_irq
Pin
該詞會盡可能地展開,直到出現多種可能為止。例如,輸入 machine.Pin.PULL 並按下 TAB,它會展開為 machine.Pin.PULL_。再按一次 TAB 就會顯示可能的展開項目:
>>> machine.Pin.PULL_
PULL_DOWN PULL_UP
>>> machine.Pin.PULL_
中斷執行中的程式¶
你可以按下 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()
...
Traceback (most recent call last):
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 直譯器,但會盡量不去重置你連接到 OpenMV Cam 所使用的方式(USB)。
你可以在 REPL 中按下 Ctrl-D 來執行軟重置,或在你的 Python 程式碼中執行:
machine.soft_reset()
例如,如果你重置 OpenMV Cam 並執行 dir() 命令,你會看到類似這樣的內容:
>>> dir()
['__name__']
現在建立一些變數並重複執行 dir() 命令:
>>> i = 1
>>> j = 23
>>> x = 'abc'
>>> dir()
['j', 'x', '__name__', 'i']
>>>
現在如果你按下 Ctrl-D 並重複執行 dir() 命令,你會看到你的變數已不再存在:
MPY: sync filesystems
MPY: soft reboot
MicroPython v1.25.0 on 2025-05-15; OpenMV Cam H7 with STM32H743
Type "help()" for more information.
>>> dir()
['__name__']
>>>
關於重置類型與啟動程序的更多資訊,請參閱 重置與開機程序。
特殊變數 _(底線)¶
當你使用 REPL 時,你可能會執行運算並看到結果。MicroPython 會把前一個陳述式的結果儲存在變數 _(底線)中。因此你可以利用底線把結果存到變數裡。例如:
>>> 1 + 2 + 3 + 4 + 5
15
>>> x = _
>>> x
15
>>>
原始模式與原始貼上模式¶
原始模式(也稱為 raw REPL)通常不是一般人會使用的功能。它是為程式化使用而設計的,基本上其行為類似關閉回顯的貼上模式,並可選擇性地使用流量控制。
原始模式使用 Ctrl-A 進入。接著你傳送你的 Python 程式碼,後面跟著一個 Ctrl-D。Ctrl-D 會以「OK」回應確認,然後 Python 程式碼就會被編譯並執行。任何輸出(或錯誤)都會被送回。輸入 Ctrl-B 會離開原始模式並回到一般的(即友善的)REPL。
原始貼上模式是 raw REPL 內的一個額外模式,它包含流量控制,並在接收程式碼的同時進行編譯。這使得高速地把程式碼傳輸到裝置中更為穩健,而且在接收時也使用較少的 RAM,因為它在編譯前不需要儲存程式碼的逐字副本(這與標準原始模式不同)。
原始貼上模式使用以下的通訊協定:
如常透過 ctrl-A 進入 raw REPL。
寫入 3 個位元組:
b"\x05A\x01"(即 ctrl-E 接著「A」再接著 ctrl-A)。讀取 2 個位元組以判斷裝置是否進入原始貼上模式:
如果結果是
b"R\x00",則表示裝置理解該命令但不支援原始貼上。如果結果是
b"R\x01",則表示裝置支援原始貼上並已進入此模式。否則結果應為
b"ra",表示裝置不支援原始貼上,此時應讀取並捨棄字串b"w REPL; CTRL-B to exit\r\n>"。
如果裝置處於原始貼上模式則繼續,否則退回到標準原始模式。
讀取 2 個位元組,這是以 16 位元無號小端序整數儲存的流量控制視窗大小遞增量(以位元組為單位)。剩餘視窗大小變數的初始值應設定為此數字。
把程式碼寫出到裝置:
當還有位元組要傳送時,最多寫入相當於剩餘視窗大小的位元組數,並把剩餘視窗大小減去已寫入的位元組數。
如果剩餘視窗大小為 0,或有一個位元組等待讀取,則讀取 1 個位元組。如果這個位元組是
b"\x01",則把剩餘視窗大小加上步驟 5 中的視窗大小遞增量。如果這個位元組是b"\x04",則表示裝置想要結束資料接收,此時應把b"\x04"寫入裝置,之後不再傳送任何程式碼。(注意:如果有一個位元組正等待從裝置讀取,並不需要立即讀取並處理它,只要剩餘視窗大小大於 0,裝置就會持續消耗傳入的位元組。)
當所有程式碼都已寫入裝置後,寫入
b"\x04"以表示資料結束。持續從裝置讀取,直到收到
b"\x04"為止。此時裝置已接收並編譯所傳送的全部程式碼,並正在執行它。裝置會輸出執行中的程式碼所產生的任何字元。當(如果)程式碼結束時,會輸出
b"\x04",後面跟著任何未被攔截的例外,然後再次輸出b"\x04"。接著它會回到標準 raw 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 個位元組,然後才需要等待或檢查更多傳入的流量控制字元。
MicroPython 遠端控制:mpremote 工具使用 raw REPL(包括原始貼上模式)來在 OpenMV Cam 上執行 Python 程式碼。