raspberrypi 官網 raspberrypi 官網

互動 IoT 系統應用 - 上課教材

互動 IoT 系統應用 > 課程內容 > 第 05 章 - python 程式設計初探

第 05 章 - python 程式設計初探

上次更新日期 2022/10/17

在樹莓派上面,一大堆的功能都可能需要透過 python 程式的支援,因此,熟悉一下簡易的 python 是很重要的。 python 程式跟以前資傳系接觸到的程式可能有很大的不同!因為 python 很要求『排列整齊』!所以, 如果『階層』對應不起來,程式碼就無法執行~相當有趣!這裡我們來簡單的接觸、玩一玩 python 吧!

學習目標:

  1. 建立第一隻 python 程式與執行它
  2. 設計變數功能
  3. 簡易的數值運算
  4. python 的 if 條件判斷
  5. python 的 for 與 while 迴圈學習

5.1: 使用 python 腳本與執行

傳統的程式語言,如 C, java, fortran 等,都需要透過『編譯』之後,才有辦法執行程式碼。許多新的程式碼,包括 javascript, PHP, python 等, 屬於直譯式程式語言,基本上,我們可以稱為『腳本』,將許多功能寫在一起,變成一整串人類可讀的程式碼, 透過外部程式的執行,即可進行運作!不需要重新編譯。雖然效能方面可能無法跟傳統程式語言比,但是, 可讀性、可攜性、便利性就變得很好!因此,許多的功能,漸漸都朝向這方面的語言靠近。

python 有很多可用的外掛模組,可以直接應用到樹莓派上,因此,熟悉 python 對於樹莓派來說,也是很重要的。 現在,讓我們來了解一下 python 腳本的寫法。

基本上, python 撰寫時,記得你的副檔名最好都寫成 OOXX.py,檔名最好都用英文與數字加上底線的組合,不要用中文或其他特殊符號比較好。 請在你家目錄底下,建立一個 python 的目錄,未來我們的腳本都放在這裡好了!此外,既然要搞 python,就得要知道目前的 python 程式碼是第幾版? 所以,我們可以這樣做:

$ mkdir python
$ cd python
$ python -V
Python 3.9.2

所以,確定有 python 程式,且版本為 3.9.2 !所謂的主版本指的是 3.9,只要你的版本高於 3.9 即可~如果是 3.6 也還行, 不要是 2.x 喔~許多指令語法會不太一樣~

  • 第一隻 python 程式,印出哈囉 python

使用 print("字串") 這個程式碼功能,就可以在螢幕上列出你要輸出的字串!寫程式第一隻通常就是哈囉世界 (hello world), 讓我們來玩一玩!檔名就稱為 hello.py 好了。

$ vim hello.py
# 這個 # 是註解
print("Hello Python")

$ python hello.py
Hello Python

在 python 程式裡面,所有在 # 後面的資料全部是註解!所以,你可以在程式腳本裡面增加一些註解,讓自己以後知道該程式的用途。 至於執行的方法,直接以『 python filename.py 』的方式來執行即可!另外,還是得要再次強調,每一行程式碼都得要對齊, 然後,如果有特殊的函數或相關的迴圈判斷式,就得要縮排!否則會出問題!

另外,如果是字串資料,則字串頭尾都需要使用雙引號來處理,否則就可能是變數名稱或者是數值型態的資料喔! 這點得要特別注意!

  • 使用變數

包括在未來我們可能會使用到的許多感測器模組,大多會使用變數的方式來提供使用者取得感測器的數值。 那什麼是變數?基本上,就是一個數學式!只是,等號的兩側中,左側永遠是未知數 (變數名稱),右側則是已知數 (變數內容)。 舉例來說,假設有公式『 y = a*x + b 』的話,那 y 這個變數可以是未知數,但是 a, b, x 就必須要先指定! 不然,式子就會發生錯誤喔!另外,我們也可以透過 print 去印出來結果!

$ vim var01.py
# 開始計算 y = a*x + b
mycal = "y=a*x+b"
x = 3
a = 5
b = 10
y = a * x + b

print (mycal)
print ("嘗試計算:"+mycal)
print (y)
print ("y =", a, "*", x, "+", b, "=", y)

$ python var01.py
y=a*x+b
嘗試計算:y=a*x+b
25
y = 5 * 3 + 10 = 25

如同一開始說的,等號兩邊左側是未知,右側是已知,所以左邊是變數名稱,右邊是變數值,這真的要搞清楚喔! 另外,字串也是可以相加的,如果一串相加的資料裡面有一個是字串,那整串都會變字串輸出。當然, 過程中很可能會有數值相加減的! print 是很萬用的輸出指令,在括號內的參數,可以是變數, 也可以直接用加號 (+) 將資料進行累加,也可以將每個變數用逗號 (,) 分隔來輸出,很多變化!

  • 特別的變數設定方式

變數名稱盡量使用英文與數字加上底線的組合,其他的符號都不要使用。另外,變數名稱開頭不能是數字, 這得要留意才行!此外,python 真的很人性化,它變數的設定方式還能有底下的特殊方式喔!

$ cp var01.py var02.py
$ vim var02.py
# 開始計算 y = a*x + b
mycal = "y=a*x+b"
print ("嘗試計算:y=a*x+b")
x, a, b = 3, 5, 10
y = a * x + b
print ("y =", a, "*", x, "+", b, "=", y)
x = a = b = 15
y = a * x + b
print ("y =", a, "*", x, "+", b, "=", y)

$ python var02.py
嘗試計算:y=a*x+b
y = 5 * 3 + 10 = 25
y = 15 * 15 + 15 = 240

上面的範例中,一個等號兩邊可以同時塞多個變數與變數值,python 會主動幫你設定好!如果變數內容相同, 那可以使用第二種方式來處理!相當有趣!另外要注意,程式當中出現兩次 y=a*x+b,這是因為兩次的 a, x, b 數值有改變, 所以當然要重新計算!要注意!要注意!

5.2; 使用 if ... else 進行條件判斷與使用 datetime 模組

寫程式碼,最需要學習的其實是邏輯概念。一般來說,邏輯就是判斷對與否 (true and false),對要做什麼,不對則要做什麼這樣。 就跟人腦一樣,會判斷是否要進行。不過,程式比較笨,大部分的時候,只會判斷『對』或『錯』而已,沒有模糊空間囉。 那如何進行對錯呢?使用 if (如果) 搭配 else (別的, 要不然) 即可。

$ vim if01.py
myday = 'monday'
if myday == 'monday':
  # 是星期一的時候
  print ("感到非常 blue")
else:
  # 不是星期一的時候
  print ("就是努力工作")

$ python if01.py
感到非常 blue

要注意的是,if 後面加的是邏輯判斷式,並不是變數給予,因此,會有兩個等號!if 的結尾 (同一行最右邊) 並不是括號,而是冒號 (:), 下一行開始是 if 的子程式碼,因此需要縮排!縮幾格不是重點,有縮排就好!之後與 if 同層級的程式碼則是 else,同樣的, 結尾需要有冒號,其下的程式碼則同樣是需要縮排!至於邏輯判斷經常使用的運算子則有:

  • X == Y
  • X != Y
  • X < Y
  • X <= Y
  • X > Y
  • X >= Y

運算子的比較,不是只有數值喔,字串也是可以比較的!只是,上面的案例有點怪~因為我們竟然手動輸入禮拜幾~好怪! 明明電腦就有時間啊!能不能讓系統自動帶入時間呢?可以的!只是,需要匯入額外模組才行!

  • 使用 datetime 模組

python 有非常多的外掛,其中一個重要的外掛,就是日期時間模組。要使用這個模組時,就得要先匯入模組資料才行! 使用的方法有點像這樣:

$ vim date01.py
# 先匯入模組,並成為 datetime 物件
import datetime

# 設定一個變數,使用 datetime 物件,該物件內使用 datetime 函數, now 為該函數功能之一
#       物件名  .函數名  .功能之一
myday = datetime.datetime.now()

# 印出目前時間
print(myday)

# 印出目前是星期幾
print(myday.strftime("%w"))

# 印出該項目的變數類型
print(type(myday.strftime("%w")))

$ python date01.py
2022-10-17 09:50:47.877555       <==日期與時間
1                                <==星期幾
<class 'str'>                    <==變數的類型為字串

這個日期模組挺有趣的,我們要先以 import 的方式『匯入』這個模組,如果你都沒有指定任何的別名, 那麼就直接拿這個模組名稱當成一個物件來處理。那個 now() 就是『現在這個時間點』的功能,如此, 就可以將這個日期推論出來。只是,最終並不是我們需要的禮拜幾。有興趣可以看一下文末的參考資料, 我們這邊可以直接說,我要取出星期 0~6 (星期 0 是星期天的意思),那就可以使用上面的 myday.strftime("%w") 來處理! 那個 strftime 可以解釋成『 string from time (時間轉成字串)』的概念,比較好記憶。

  • 日期結合條件判斷,自動判斷星期幾

來改變一下我們剛剛的條件判斷式吧!

$ cp if01.py if02.py
$ vim if02.py
import datetime                      # 匯入時間模組

myday = datetime.datetime.now()      # 取得目前的時間
wday  = int(myday.strftime("%w"))    # 由上面的變數取得星期幾

if wday == 1:                        # 調查是不是星期一
  # 是星期一的時候
  print ("感到非常 blue")
else:
  # 不是星期一的時候
  print ("就是努力工作")

$ python if02.py
感到非常 blue

這樣看起來算是比較合理的狀態!

  • 使用 if ... elif ... else 進行多重條件判斷

在仔細想想,剛剛的範例還是不太合理~如果是星期六、日,明明就可以休息,結果竟然寫需要努力工作!不太恰當... 所以,我們應該要判斷特別的星期一,普通的星期二到星期五,假日的星期六日。因為會有複合的運算子,因此就得要有 and 以及 or 的支援! 同時,多重條件判斷,就需要 elif (else if 的縮寫) 的支援!所以,上面 if 的範例,進一步變成這樣:

$ cp if02.py if03.py
$ vim if03.py
import datetime

myday = datetime.datetime.now()
wday  = int(myday.strftime("%w"))

if wday == 1:
  # 是星期一的時候
  print ("感到非常 blue")
elif wday >=2 and wday <=5:
  # 星期二到五要努力
  print ("就是努力工作")
else:
  # 不是星期一到五,當然就是假日
  print("好好玩、好好休息、好好充電")

需要測試的話,可以在 wday 底下額外指定 wday = 0 之類的方式來測試!測試完畢就可以註解該行!這樣, 才有辦法處理程式碼的確認~否則,難道真要每天運作?哈哈!那是沒道理的!因此,很多時候,你會發現, 程式設計過程中,許多的『測試』得要花費心思去處理!另外,python 真的很有趣!它可以跟人類寫的判斷式一樣, 使用如下的方法來處理:

#elif wday >=2 and wday <=5:
elif 2 <= wday <=5:

不過,這種寫法畢竟好像只有特殊的腳本程式語言才支援,一般還是透過 and 或者是 or 連結兩個條件判斷處理, 建議還是不要使用這種偷懶的方式處理啦!呵呵!

5.3; 使用 for 迴圈搭配數值 range() 與字串陣列

如果你要算一大堆連續的資料,總不會一筆一筆數字輸入吧!那有沒有辦法『連續輸出一串數值』呢?可以的!使用 range 即可! 這個 range 的使用方式大致上是這樣:

range(10)       # 代表 0, 1..., 9,注意,是 0 到 9 ,不含 10 喔!
range(10,16)    # 代表 10, 11..., 15,不含 16 喔!
range(0,101,5)  # 代表 0, 5, 10...100,間隔為 5 喔!

也就是說,range 預設的起始數值是 0 ,而預設的步階 (step) 是 1,除非你有額外指定,否則數值如上所示。 所以,如果你要輸出 1...9 的話,使用 for 迴圈來搭配 range 的使用即可。那麼 for 是什麼呢?基本上, for 就是指定一個變數,該變數可以進行好多次,次數由 range 來指定的意思!

$ vim for01.py
for i in range(1,10):
  print(i)

$ python for01.py
1
2
...
9
  • 巢狀迴圈進行九九乘法表

計算九九乘法表列表,不用格式排列漂亮,很簡單的處理!

$ vim for02.py
for i in range(1,10):
  for j in range(1,10):
    print( str(i) + ' x ' + str(j) + " = " + str(i*j) )

$ python for02.py
1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
1 x 4 = 4
....
9 x 7 = 63
9 x 8 = 72
9 x 9 = 81

在 print 的輸出中,所有資料的格式需要相同,才可以使用 + 來累加!所以,我們得要將 i 與 j 純數值轉成字串,使用 str(i) 的方式來轉! 這樣就 OK 了!可以格式化輸出一堆資料哩!

  • 字串使用陣列的迴圈方式

數值可以透過 range 來提供,那文字呢?基本上,文字或數值,都可以透過陣列來處理。要注意的是, python 的陣列格式非常多樣! 我們使用單純的 list 格式處理!假設星期一到星期五學校午餐湯品要依序列出,那可以這樣處理:

$ vim for03.py
soup = [ "牛蒡雞湯", "玉米蛋花湯", "芹菜餛飩湯", "薑絲海苗湯", "綠豆薏仁湯" ]
i = 0

for ss in soup:
    i=i+1
    print("星期 " + str(i) + " 喝的湯:" + ss)

$ python for03.py
星期 1 喝的湯:牛蒡雞湯
星期 2 喝的湯:玉米蛋花湯
星期 3 喝的湯:芹菜餛飩湯
星期 4 喝的湯:薑絲海苗湯
星期 5 喝的湯:綠豆薏仁湯

陣列 (list) 使用中括號包含數個字串,字串間以逗號 (,) 隔開即可!

5.4; 使用 while 迴圈搭配 break 與 continue 功能

相對於 for 迴圈算是固定次數的迴圈,while 迴圈則通常需要搭配判斷式來處理,亦即,只有在條件規範的環境內, 才會進行迴圈,否則就不會進行迴圈這樣的意思!我們先來做個簡單的處理,例如要算出 10! 這個 1x2x3...x10 的數值, 如果用 while 時,可以這樣計算:

$ vim while01.py
i=1
j=1

while i <= 10:
  j = i*j
  i=i+1

print(j)

$ python while01.py
3628800
  • 使用內部 continue 與 break 進行 while 控制

除了指定限制之外,我們也可以在 while 迴圈使用兩個控制參數來處理!

  • continue:直接跑去下次迴圈,本次迴圈中止
  • break:結束 while 的迴圈運作

舉例來說,我們要輸出星期一到星期七(就是星期天),但是星期三不輸出,那可以這樣進行:

$ vim while02.py
i = 0

while True:
    i=i+1
    # 星期三不要輸出
    if i == 3:
        continue
    print ("星期 " + str(i))
    # 已經 7 天了,結束輸出
    if i >= 7:
        break

print("結束輸出")

$ python while02.py
星期 1
星期 2
星期 4
星期 5
星期 6
星期 7
結束輸出

因為 while 後面接了 True,這代表 while 迴圈如果沒有控制的話,那就會一直跑下去.... 因此後續加上 continue 與 break 來限制,才有辦法將 while 迴圈中斷呢!

5.5: 當週實做

  1. 雖然我們有萬年曆,但假設我還是需要列出來某年某月的每一天是星期幾,這時就得要搭配變數與迴圈處理! 假設 yy 代表設定為年, mm 代表設定為月,而 dd 就代表為日,你要指定的是 yy 與 mm,而 dd 請使用到 28 就好 (目前不防呆)。 dd 應該會是迴圈內的變數才是。而推算出星期幾的方式,例如 2022/10/10 的物件,可以這樣設定:
    myday = datetime.datetime(2022, 10, 10)
    
    最終執行輸出,假設是 2022 年 10 月份時,輸出的結果會有點像這樣:
    $ python unit5.py
    2022-10-01 是星期 6
    2022-10-02 是星期 0
    ....
    2022-10-27 是星期 4
    2022-10-28 是星期 5
    
  • 參考資料

...