Files
microbit-micropython-cookbook/guide/learn-python-on-microbit-zh.md
2021-02-08 17:31:26 +08:00

12 KiB
Raw Blame History

在 BBC micro:bit 上學 Python

Alan Wang, Feb 2021

本指南採用 GNU 3.0 通用公共授權

01

關於本指南

這份指南不是替兒童而寫,而是有興趣使用 BBC micro:bit 開發板為媒介來學習 Python 語言的成人或青少年。

現有的書籍或網路教材,在談及 micro:bit 的 Python 教學時,多半著重在 micro:bit 的功能和相關的範例,卻鮮少深入 Python 的語言特色。這份指南的目的是借用 micro:bit 的硬體特色來介紹 Python 的重要概念,好讓學習者將來能將之應用在正式的 Python 程式開發。

至於 micro:bit 是什麼、為什麼現在要學 Python這些在網路上已經有非常多討論這裡就不再贅述。

閱讀本指南所需的準備

本指南會使用 2020 年 10 月後上市的新版 micro:bit V2,但大部分程式碼也適用於 V1。筆者推薦使用 V2因為價格相近但規格更佳有更多記憶體執行 Python 直譯器。

你也需要 micro USB 線以及一台有 Google Chrome 瀏覽器的電腦,就這樣。不須安裝其他東西。

Python 編輯器

打開 https://python.microbit.org/v/2

02

這是 micro:bit 官方提供的線上版瀏覽器,雖然簡單,但就本指南的目的來說夠用了。後面有機會的話,筆者會在談如何使用其他 Python 編輯器。

畫面上方有五個大按鈕:

  • Download/Flash (下載/燒錄)
  • Connect/Disconnect (連線/解除連線)
  • Load/Save (上載檔案/存檔)
  • Open Serial/Close Serial (打開 REPL/關閉 REPL)
  • Help (線上說明)

按鈕的內容會因與 micro:bit 連線與否而有所不同。

與 micro:bit 連線和燒錄第一支程式/韌體

Python 是直譯式語言,這表示程式運作的地方必須裝有直譯器。幸好,官方編輯器簡化了這個流程:你從編輯器下載的 .hex 程式檔中,有一部分會包著 micro:bit 用的 Python 韌體,剩下的則是你寫的程式(又稱草稿碼)。即使你的 micro:bit 之前並沒有安裝 Python 韌體只要燒錄一次程式就會自動完成韌體安裝。這也使得第一次燒錄──或者在使用過其他語言後重新燒錄──Python 會花較久的時間。

micro:bit 使用的 Python 實際上是 Micropython──設計給記憶體有限的開發版的 Python 版本。Micropython 本身就有好幾種版本,針對不同類型的開發板而作,不過它們都是是以 Python 3.4 為基礎。所以Python 3.4 擁有的核心語言功能,在 micro:bit 都是可以使用的。

那麼,我們就來燒錄一支程式,直接用官方編輯器一打開就出現的程式即可:

# Add your Python code here. E.g.
from microbit import *


while True:
    display.scroll('Hello, World!')
    display.show(Image.HEART)
    sleep(2000)

將 micro:bit 接上電腦,然後按畫面中的 Connect,讓 Chrome 瀏覽器跟你的裝置連線:

05

連線後按 Flash。等待程式燒錄作業結束。

較近期的 micro:bit 的韌體支援 WebUSB讓瀏覽器能跟 USB 裝置連線,這麼一來編輯器就能直接下載程式到 micro:bit 上。現在市售的 micro:bit 應該都有新韌體了;但若你沒辦法連線,請用 Download 下載 .hex 檔後複製/貼上到 micro:bit 的 USB 磁碟區。

REPL 互動介面

想學 Python就不可不知 REPLRead-Eval-Print Loop讀取-求值-輸出循環)。簡單說,這是 Python 直譯器的互動介面,能讓開發者用來做簡單的測試、探索 Python 的功能、讀取程式的回應等等,不管在電腦或開發板上,對程式開發者來說都是很實用的工具。因此後面在講解 Python 入門時,我們會先在 REPL 下來示範。

在 micro:bit 連線的情況下,點編輯器的 Open Serial然後點按鈕下方右側的「Send CTRL-C for REPL」或直接在鍵盤上按 Ctrl+C。你應該會看到以下畫面

04

這幾行文字

MicroPython v1.13 on 2020-12-21; micro:bit v2.0.0-beta.3 with nRF52833
Type "help()" for more information.
>>> 

就是 REPL 的提示,類似 Windows 命令提示字元或 Unix 的終端機。它告訴我們 Python 直譯器的版本,並等待我們輸入指令。

現在於 >>> 後面輸入 1 + 2並按 Enter

MicroPython v1.13 on 2020-12-21; micro:bit v2.0.0-beta.3 with nRF52833
Type "help()" for more information.
>>> 1 + 2
3

可以發現 Python 直譯器解讀了你輸入的程式,並自動算出答案。

Python 基礎:運算式

在 Python 中,程式碼可分為兩類:陳述statement運算式expression。這兩者都會執行某個功能,但運算式本身也代表某個值,比如前面的 1 + 2 會得到 3

運算式可以放在其他運算式中,而 Python 有很多會傳回值的東西都可以當成運算式的一部分。最簡單的運算式由值和**運算元operator**構成,例如上面的算式有數字 1 和 2中間是加號運算元+)。

我們先來看 Python 常用的運算元:

功能 Python 運算元
+
-
*
/
整數除 //
餘數除 %
次方 **
小括號 ()

在 REPL 中試試看:

>>> 2 + 3
5
>>> 2 - 3
-1
>>> 2 * 3
6
>>> 10 / 3
3.333333
>>> 10 // 3
3
>>> 10 % 3
1
>>> 2 ** 3
8
>>> 10 / (2 + 3)
2.0

數字與運算元之間一定要有空格嗎?不用,甚至打一堆空格都無所謂,但留一個空格是最美觀的。

Python 基礎:資料型別

前面的運算式,其實只使用到數字而已。而在 Python 中,不同的資料有不同的型別type,而型別決定了資料(以及你對資料)能做哪些事。

Python 最基本的幾種型別為:

型別 | 範例 int (整數) | 42 float (浮點數) | 3.14159 str (字串) | "test" bool (布林值) | True/False NoneType (無值) | None

整數與浮點數

以上面的運算元來說,整數(無小數點)和浮點數(有小數點)是可以放在一起運算的,而取決於運算元,結果會是整數或浮點數。例如,整數用 / 相除會得到浮點數, 用 // 相除卻會得到整數。

如果用 // 時算式裡有浮點數呢?這樣就還是會得到浮點數:

>>> 10 // 3.0
3.0

字串

字串前後必須用雙引號 (") 或單引號 (') 括起來:

>>> "This is a string"
'This is a string'

Python 預設是用單引號,不過大多時候沒有差別,取決於個人習慣。單引號看起來比較簡潔,但雙引號在多數語言是表示字串的通用用法。其實 Python 還有幾種其他代表字串的變形形式,不過一開始不需要知道。

當然,字串內容可以打任何語言。不過 micro:bit 的網頁編輯器打中文有點容易亂跳,所以還是打英文吧。

字串和整數、浮點數最大的差別,在於它們不能放在一起運算:

>>> 1 + 1
2
>>> "1" + "1"
'11'
>>> 1 + "1"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported types for __add__: 'int', 'str'
>>> "1" + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't convert 'int' object to str implicitly

當你把數字寫在用 " 或 ' 括起來的字串中,那些數字就是字串而不是數字了。當你對兩個字串使用 + 號,這些字串只會直接連在一起。

這顯示了 + 運算元對數值和字串的意義是不一樣的,所以你嘗試執行 1 + "1""1" + 1 就產生錯誤了。之後我們會再談到怎麼藉由轉換資料型別的方式,好讓它們可以一起運算。

執行遇到問題時Python 直譯器會顯示錯誤訊息,告訴你錯誤發生的行數(由於我們在使用 REPL 介面,所以位置是第 1 行以及原因TypeError型別錯誤。這時我們就可以根據這些訊息來嘗試排解錯誤除錯

布林值

布林值Boolean就是「是否」或「真假」的二元結果在 Python 中這兩個值分別是 True 和 False第一個字一定大寫主要用在邏輯判斷用途這些後面會再探討。

Python 的布林值同時也是一種特殊的數值0 和 None 就等於 False除此以外的其他任何數字則等於 True。

None

None 是個特殊的值,代表沒有值的意思。你用到它的機會非常少,但有些 Python 功能會把它當成沒有值時的預設值。

Python 基礎概念:變數

宣告變數

**變數variable**是用來在程式中記住資料的方法,就像是解數學方程式時的 X 或 Y。變數會有一個值而這個值是可以隨意改變的。

在 Python 中若要宣告define一個新變數辦法是用 =(指派運算元)號指定或賦予一個值給某個名稱:

>>> a = 1

此舉建立了名為 a 的變數,值為整數 1。

>>> a
1
>>> a + 3
4

如果用 = 指定新的值給 a它的值會隨之改變

>>> a = 2
>>> a
2
>>> a * 3
6

你甚至可以這樣寫:

>>> a = 1
>>> a
1
>>> a = a + 4
>>> a
5

請記住 = 號不是數學上的等於,而是將其右邊的值指定給左邊。一開始 a 的值為 1然後我們指定新的值 a + 4也就是 5 給 a。因此 = 完成運算後a 就變成 5 了。

最後,來按編輯器的 Close serial 關閉 REPL 介面,然後重開(記得按 Ctrl+C並再次輸入 a 查詢其值:

>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' isn't defined

現在產生了錯誤,說名稱 a 未定義。這是因為重開 REPL 後,變數 a 就在記憶體裡消失了。

後面我們在執行完整的程式時,每次重新執行的效果就等同於重新啟動 REPL所以你得在程式裡適當的地方宣告變數後面的程式使用它時才不會遇到問題。

Python 變數是個「路牌」

現在要來講一個比較難懂、但仍然非常重要的觀念,因為這能解釋 Python 變數在賦值時的極大彈性。

在許多程式語言中,變數是個容器,實際上就是記憶體裡的一個空間,然後把值存在那裡面。既然是事先指定的空間,你只能用它來儲存特定類型的資料。

但 Python 的做法卻剛好相反:值本身已經存在於記憶體中某處了,你所做的其實是做一個「路牌」來指向它。

a = 1 為例,整數 1 其實已經存在於記憶體內,我們只是新增一個名稱 a 來代表它。而當你執行 a = 2 時,路牌 a 會指向記憶體中的整數 2。這時整數 1 仍然存在,只是除了直接寫出 1 以外,我們沒有別的方式能引用 1。換言之變數可以指向任何資料就算途中改變資料的類型也無謂

>>> a = 1
>>> a
1
>>> a = "test"
>>> a
'test'

上面 a 一開始是整數,後來變成字串了。事實上 Python 變數可以指向各種東西,其彈性

當然,整數 1 和 2 等等是特例,它們是 Python 一開始就擁有的資料。有些資料是由使用者在執行程式期間建立的。這些資料

Python 變數的命名規則

Python 變數的命名非常自由,除了不能用數字開頭以外,可以隨意混搭字母、數字和底線:

>>> _Number_01 = 42
>>> _Number_01
42

Python 變數名稱也支援 Unicode因此使用中文、日文或各國語言都是可行的。使用非 Unicode 特殊字元會產生錯誤。不過,一般習慣上還是會以英數為主,而且最好能清楚反映變數本身的用途。

當然還有一個你不應該做的事,就是使用 Python 內建功能的名稱來當變數。這會導致那個名稱指向了你給予的資料,結果原本的功能就沒辦法用了,可能還會導致程式錯誤。 的

(持續寫作中...