又是喝咖啡學程式系列,這次是學 Python。筆記內容包括基礎與進階兩堂課。
Codefree Time(圖片來源: Hiskio Codefree)
CH 1|關於 Python 的那些大小事
1-1|Python 之父為什麼創造 Python?
這個我知道!聽說是聖誕節的時候太無聊而設計出來的語言,超狂的有沒有!
吉多·范羅蘇姆(Guido van Rossum)(圖片來源: TechOrange)
Python 之父名為吉多·范羅蘇姆(Guido van Rossum),而 Python 是他在 1989 年聖誕假期時為了打發時間的產物。是說,這位仁兄閒起來有多狂?我上一次看到他的消息就是因為他說退休太無聊了,準備去微軟打工!
Python 設計哲學是 「優雅」 、 「明確」 、 「簡單」。它將許多的細節隱藏交由直譯器處理,讓程式設計師可以專注於思考程式邏輯而不是具體的實做細節。
有句 Python 的 Slogan:「人生苦短,我用 Python (Love is short, use python)」,這句話也側面說明了 Python 語法簡單與高效。
人生苦短,我用Python (Love is short, use python)(圖片來源: 壹讀)
另外課程中提到,Python 擁有「可擴充」使用的彈性,我想這應該是在說明它的第三方套件?
測驗與練習
-
請問下列何者並非為Python的設計哲學
- 簡單
- 明確
- 快速
- 優雅
1-2|程式的開端:向世界說你好!
兩個重點:
- Python 的標準輸出是
print()
- 輸出內容以引號將其包圍,雙引號或單引號皆可,但必須成對出現。
使用 print()
螢幕輸出:
1 |
|
結果:
1 |
|
是說第一個程式寫 Hello World!的傳統是從哪裡來的?
測驗與練習
-
完成程式缺少的元素
請觀察以下程式,完成程式缺少的部分並執行。1
Hello~
答:
1
print("Hello~")
-
使用
print()
新增文字
承上題(保留上一題的程式),請新增新的 print() 在原有的程式碼下,並輸出「Today is a good day」。1
2Hello~ Today is a good day
答:
1
2print("Hello~") print("Today is a good day")
1-3|多行輸出:幾個 print 就幾行輸出
Python 在識別程式指令時,是由上往下逐一識別。理論上,呼叫幾次 print 就輸出幾行。
我會說理論上是因為…如果我在輸出內容插了換行符號的話,這到底算幾行?
多行輸出指令
1 |
|
結果:
1 |
|
測驗與練習
-
若電腦執行以下程式,請問總共會輸出幾行結果?
1
2
3print("Hi") print("My name is HiSKIO") print("Nice to meet you!")
- 3行
- 1行
- 5行
1-4|工程師的小幫手,論註解的重要性
在電腦語言中,註解(comment)是重要的一個組成部分。
在 Clean Code 一書有提到:
註解雖可以告訴別人你程式碼的目的,也能增強程式可讀性、可維護性,但除了一些合適的註解,如法律、資訊補充、意圖解說與闡釋外,單純使用程式碼就能表達意圖是最好的。如果是因為程式的函式、命名…等原因,讓人無法輕易理解開發者意圖,需花費大把時間寫註解的,可能重寫程式碼比較快 XDDD
等等,這邊不是 clean code 的讀書心得,先回到課程上。總之註解,好的註解可以幫助理解程式,在 Python 中,用 一個井號 #
做單行註解、用 三個雙引號 "
或 三個單引號 '
做多行註解。
註解指令
1 |
|
不管是哪種註解方式,註解內容不會執行,因此輸出皆為空白。
測驗與練習
-
使用「單行註解」符號完成註解
有一程式需要請你幫忙註解一行程式,請註解程式print("Hello World"!)
,其餘照常輸出。答:
1
2
3# print("Hello World!") print("Nice to meet you") print(1)
-
運用「多行註解」符號註解程式
承上題,請利用多行註解方法,註解程式碼,註解內容為「前兩行程式碼」,其餘照常輸出。答:
1
2
3
4
5''' print("Hello World!") print("Nice to meet you") ''' print(1)
1-5|你不知道你錯,那就電腦告訴你錯!
當撰寫的程式不符合語法時,會得到程式語法錯誤的錯誤訊息。
1 |
|
結果:
1 |
|
另外,錯誤訊息通常會提示錯誤在第幾行附近,甚至是哪個位置,仔細觀察訊息可以快速排除錯誤。
1 |
|
測驗與練習
-
SyntaxError 代表?
- 程式未執行
- 程式輸出資料有誤
- 程式語法錯誤
CH 2|創造變數
2-1|資料取名字:變數
變數提供具名稱的記憶體儲存空間,具有唯一性。
因 Python 的語言動態型別特性,在使用該變數前毋須宣告變數,其資料型別會根據被賦值的型別來自動定義。在建立變數時,只須給出變數名稱(name
),並使用賦值運算子(=
)進行賦值("HiSKIO"
)。範例如下:
1 |
|
在訂定變數名稱須遵守 Python 的變數命名規則:
- 變數首字元須為英文字母或底線字元。
- 除首字元外,其他字元僅能為英文字母、底線字元或數字。
- 不能是保留字,類似 int 之類的。
其他的大、小蛇式命名法…之類的使用規則應該算是 Coding Style?可以看看我之前寫的 Python Coding Style。至於課程中提到的以「使用目的」去命名,這…應該不算命名規則,這是命名常識吧 XDDD
測驗與練習
-
良好的變數命名習慣有助於整體程式更有架構,在閱讀時也能更方便。請觀察程式,選擇變數「today」儲存資料值為何?
1
2
3name="HiSKIO" color="blue" today="Saturday"
- HiSKIO
- Saturday
- blue
2-2|變數的輸出
使用變數最大的好處是,當需要運用該資料時,可以直接呼叫變數名稱得到該值,毋須重複撰寫資料內容與計算。
輸出儲存於 name 這個變數的內容
1 |
|
結果:
1 |
|
若改動變數內資料,則輸出結果也會跟著變動。舉例來說將 name
值由 「HiSKIO」 改成 「Hi」,結果如下:
1 |
|
結果:
1 |
|
引用變數時必須完全正確。若引用錯誤會被視為使用未宣告變數,因而找不到對應資料輸出,出現 NameError 的錯誤。
1 |
|
結果:
1 |
|
若要做資料拼接,可在輸出時使用逗號來拼接變數。
1 |
|
結果:
1 |
|
若使用多個逗號,在輸出時會依照順序,由左至右疊加。
1 |
|
結果:
1 |
|
說到做字串拼接,如果複雜點的字串我應該會用字串格式化或是字串插值的方法,這兩個寫起來可讀性比較好,就是得注意一下 Pytnon 版號。
1 |
|
結果:
1 |
|
測驗與練習
-
請觀察程式,請問輸出為何者?
1
2name="HiSKIO" print("Hello",name,"!")
- Hello HiSKIO !
- Hello name !
CH 3|資料型態
3-1|Python 世界中的資料型態與種類
Python 資料型別有以下幾種:
- 數值型態(Numeric):int, float, bool, complex
- 字串型態(String):str, char
- 容器型態(Container):list, set, dict, tuple
其中比較常用的資料型態,如下:
中文 | 英文 | 說明 | 舉例 |
---|---|---|---|
文字 | string | 用引號包圍的資料內容 |
"Hello~Hiskio!" 'Hi~'
|
整數 | int | 常見的阿拉伯數字 | 5 |
浮點數 | float | 含小數的阿拉伯數字 | 0.23 |
布林值 | boolean | True or False,首字母大寫 | True |
串列 | list | 具備順序性的集合 | ["apple","orange","pineapple","grape"] |
字典 | dictionary | 由鍵(key)和值(value)構成 | {"name":"王小明","id":249,"age":22} |
測驗與練習
-
請觀察程式,並選擇變數 number 儲存的資料型態為何?
1
number="5"
- 文字
- 數字
- 布林值
3-2|資料型態:文字
在賦值文字變數時,可使用引號來表字串的資料型態,雙引號 ""
或單引號''
都行,Python 沒有用這個來區分字串或字元。
像我自己習慣最外層是雙引號,我同事的話則是保留 C 習慣,字元用單引號、字串用雙引號,反正整個專案記得統一就好,不統一也不會怎樣,就是逼死處女座而已。
若引號內沒有任何資料,則稱為空字串。
1 |
|
字串可透過加號由左至右拼接。
1 |
|
結果:
1 |
|
教材中說到,對於數學四則運算符號(+ - * /
),文字只支援「加號」符號。我想它這句話的意思,是說只有加號能支援被加數跟加數都是文字,其他的運算符號無法,會直接迸出 TypeError。
但若是被乘數是文字、乘數是數字,這情況是成立的:
1 |
|
結果:
1 |
|
測驗與練習
-
以變數設立字串
請用變數 color 設立一個字串,儲存「blue」並輸出變數 color。答:
1
2color="blue" print(color)
-
使用加號完成文字相加
請設計一道程式,觀察以下執行後的結果格式,將文字相加,變數 color 與 data 分別儲存「blue」與「book」。答:
1
2
3color="blue" data="book" print(color+data)
3-3|資料型態:數字
Python 常見的數字型態有整數 int 和浮點數 float 兩種。跟其他語言不同,Python 浮點數並沒有單雙精度,也就是 float 與 double,的區別。不過 Python 中的 float 與其他程式語言中的 double 具有相同的精度。
兩兩數字資料型態可以任意使用四則運算符號進行運算,不過當整數和浮點數互相運算時得出結果會是浮點數。
1 |
|
結果:
1 |
|
對了課程中沒提及,這些運算符號稱為 運算子(operator),而用來算術計算的被特稱為 算術運算子(arithmetic operator) ,而常見的算術運算子除四則運算符號外,還包括取商數、取餘數跟次方三種。
運算子 | 功能 | 範例 |
---|---|---|
+ | 加 | a + b #8+5=13 |
- | 減 | a - b #8-5=3 |
* | 乘 | a * b #8*5=40 |
/ | 除 | a / b #8/5=1.6 |
// | 取商數 | a // b #8//5=1 |
% | 取餘數 | a % b #8%5 取餘數 3 |
** | 指數 | a ** b #8的5次方=32768 |
上述這種運算式(expression)是由兩個運算元(operand)與一個運算子所構成。最後的計算結果可依需求直接輸出、賦值到新的變數或寫回原變數。
1 |
|
如果是寫回原變數,可省略被運算元,將運算子後面加上 =
:
1 |
|
進行除法運算時,得注意除數不得為 0。在數學上除以 0 沒有意義,但在電腦中除以 0 它會直接掛給你看:
1 |
|
結果:
1 |
|
恩…好像也不一定直接掛,看語言跟資料型別吧。像是 Java 除以 0 也是得 error、除以 0.0 會得 infinity、0 除以 0 則會得到 NaN。Javascript 好像也是,不過 Python 必掛掉就是了。
測驗與練習
-
有兩個變數 a 與 b,分別儲存 7 和 9,請觀察輸出結果,找出使用的四則運算符號
1
2a=7 b=9
輸出結果
1
-2 40353607
-
a-b , a*b
-
a+b , a%b
-
a+b , a//b
-
a-b , a**b
-
CH 4|流程控制
4-1|識別程式碼的好夥伴 — 縮排
Python 是個採用越位規則 的程式語言。該種語言是透過縮排來表示區塊,而非大括號或關鍵詞來確定結構;也就是說,在 Python 中 同樣的縮排代表其程式是同一個區塊。因此當你縮排錯誤,Python 會毫不留情地給你報錯:
1 |
|
結果:
1 |
|
在課程中它是 Tab 來縮排,不過要注意的是 Tab 在不同的環境、不同的編輯器開啟,所呈現的效果會不同,可能會被展開成空格,有的不會,即便展開成空格也有 4 個或 8 個的長度區別。記得有一次進 code 就是因為這樣產生了 conflict。
所以你說我是空白派的嗎?其實不算,因為我習慣按 Tab 縮排;但你說我是 Tab 派的嗎?也不算,因為我會習慣調整 IDE 讓它在按下 Tab 時插入 4 個空格。不管哪一派,反正你統一一種用就是了。
雖然我記得看過人家的實驗兩種混用是也行,就是得算好 Tab 跟空格的數量,但如果你真的這樣搞絕對會被其他開發者爆打的 XDDD
縮排,Tab 還是空格?(圖片來源: Naidile (@_Naidile) / Twitter)
測驗與練習
-
請選出縮排的使用用意與對應的鍵盤按鍵
- 用意:區分程式碼、對應按鍵:Backspace
- 用意:成立流程控制、對應按鍵:Tab
- 用意:區分程式碼、對應按鍵:Tab
4-2、if 流程控制
if 的流程控制簡單來說就是如果符合什麼條件就去做什麼動作。而在程式語言書寫方面,會有條件式、冒號與縮排等元素,一旦括號內條件成立時,則執行縮排內的程式。
1 |
|
以一個生活化的例子來說:「如果期中考數學考了100分,媽媽就會獎勵我一塊雞排」,將它撰寫成虛擬碼則會變成:
1 |
|
在進行條件判斷時會用到 關係運算子(Relational operator) 或稱 比較運算子(Comparison operator) 來比較兩數間的關係。
關係運算子 | 意義 | 使用範例 | 範例運算結果 |
---|---|---|---|
== | 等於 | 1+1 == 2 | True, 1 |
!= | 不等於 | 3 != 4 | True, 1 |
> | 大於 | 5 > 6 | False, 0 |
>= | 大於等於 | 7 >= 8 | False, 0 |
< | 小於 | 9 < 10 | True, 1 |
<= | 小於等於 | 10 <= 10 | True, 1 |
將前面的虛擬碼用關係運算子來撰寫的話會變成:
1 |
|
現在寫習慣了是還好,但剛開始學寫程式的時候常常把等於的運算子打成 =
,每次都 debug 好久 XDDD
說到錯誤,這部分在撰寫時常見的錯誤不外乎是少冒號或縮排錯誤,不過這些錯誤都能從錯誤訊息得知:
1 |
|
結果:
1 |
|
或是
1 |
|
結果:
1 |
|
測驗與練習
-
使用 if 流程控制判斷餘數
請設計一支程式,設立兩個整數變數 a 與 b , a 與 b 分別儲存 10 與 5 判斷兩個變數相除(a/b)餘數是否為 0 ,若餘數為 0,輸出餘數為 0。答:
1
2
3
4
5
6a=10 b=5 #a除以b的餘數等於多少為整除~,注意if架構符號 if(a % b == 0): print("餘數為0")
4-3|else 例外處理
有 if 怎麼會沒有 else 呢 XDDD
在未達成條件時,也有觸發相對應的情況,因此可以用 else 來控制程式。
1 |
|
結果
1 |
|
測驗與練習
-
else 例外情況
承上單元實作練習,請設計一支程式,設立兩個整數變數 a 與 b , a 與 b 分別儲存 11 與 5,判斷兩變數餘數是否為 0,若兩整數相除後餘數為 0,輸出餘數為 0 ;若兩整數相除後餘數不為 0,請輸出餘數不為 0。答:
1
2
3
4
5
6a=11 b=5 if(a%b==0): print("餘數為0") else: print("餘數不為0")
4-4|elif 多重流程控制判斷
不過現實生活並非非黑即白,是會出現許多的可能。例如:媽媽說考 100 分,獎勵雞排;若沒有 100 分但有 90 分以上,就獎勵杯珍珠奶茶:連 90 分都沒有就只能空手而回了。
這種情境下 if...else...
可能會不好使,改使用多重判斷的 elif
會是比較好的選擇:
1 |
|
電腦在進行判讀時,是由上往下執行:
- step 1:先判斷 score 是否等於 100,達成條件就停止判斷,沒有達成條件則往下繼續執行。
- step 2:是否大於等於 90,達成則不會繼續往下執行。
- step 3:皆無達成上述條件,停止執行。
測驗與練習
-
符號多重條件判斷
請幫忙設計一個計算機程式,判斷變數 notation 中儲存的四則運算符號,變數 notataion 儲存為「+」。若 notation 儲存為「+」,則輸出「符號:加」;notation儲存為「-」,則輸出「符號:減」;notation儲存為「*」,則輸出「符號:乘」;notation儲存為「/」,則輸出「符號:除」
答:
1
2
3
4
5
6
7
8
9notation="+" if(notation=="+"): print("符號:加") elif(notation=="-"): print("符號:減") elif(notation=="*"): print("符號:乘") elif(notation=="/"): print("符號:除")
嘖嘖,Python 沒有 Swich-case 可以用。
4-5|巢狀 if 流程控制
多層的條件判斷可稱為巢狀 if 流程控制,簡單來說來說,就是在條件成立後再做另一層條件判斷。在寫這種結構的時候,更需要注意同樣縮排的程式碼為同一區塊,當然冒號也別忘了:
1 |
|
是說,如果你覺得巢狀多到難以閱讀,或是已經會混淆縮排的狀況,真心建議重構你的程式碼 XDDD
一樣來個傷媽媽荷包的範例:「若媽媽規定期中考數學考 100 分而且國文也考 100 分,就獎勵雞排和泡芙。」
1 |
|
是說,它的範例程式碼有點問題。如果這樣寫最終輸出結果會是:
1 |
|
因為它 Step3 那行輸出並沒任何條件判斷,換句話說只要達成 Step1 的條件後,Step3 就一定會輸出。如果按照題意改的話,應該要多加一個 else:
1 |
|
測驗與練習
-
巢狀 if 流程控制判斷贈品
請設計一支程式判斷,消費者是否得到贈品,變數 totalcash 與 purchase 分別儲存「1000」與「鳳梨」,規則如下:- 若消費者購買金額達「1000元」,而且購買物為「鳳梨」,則輸出「環保購物袋」
- 若消費金額未達 1000 元,則直接輸出「無贈品」
答:
1
2
3
4
5
6
7totalcash=1000 purchase="鳳梨" if(totalcash==1000 and purchase=="鳳梨"): print("環保購物袋") else: print("無贈品")
呃…寫完才發現不合題意,沒用巢狀結構。算了不理它了。
4-6|符號 and 與 or
像剛剛那種簡單條件判斷,很少會把它拆成巢狀來寫,更多時候會用邏輯運算子(Logical operators),來釐清所有條件之間的關係。常用的邏輯運算子有and
、or
和 not
三種,運算的結果不是 True
就是 False
。
讓我們繼續獻祭媽媽的錢包
- 條件皆達成: 數學考100分 而且(and) 國文考100分 → 獎勵雞排和泡芙
-
條件其一達成: 數學考100分 或者(or) 國文考100分 → 獎勵雞排
1
2
3
4if(math_score==100 and chinese_score==100): print("獎勵雞排和泡芙") elif(math_score==100 or CH chinese_score==100): print("獎勵雞排")
題外話,如果兩邊運算元都是布林值的情況下,這時 and
跟 or
會跟位元運算子的 &
和 |
等價。不過還是別這麼做會比較好,小心把自己給搞混了。
測驗與練習
-
使用 and 或 or 符號完成流程控制判斷
請設計一支程式判斷,根據下列規則,判斷消費者得到贈品的狀況,變數 totalcash 與 purchase 分別儲存「1000」與「葡萄」,並善用 and 與 or 的用法。- 若購買金額達「1000元」,而且購買物為「鳳梨」,兩者皆達成則輸出「環保購物袋」
- 若購買金額達「1000元」,或者購買物為「鳳梨」,達到其中一個規則,則輸出「鳳梨軟糖一顆」
- 若上述規則皆未達到,則輸出「無贈品」
答:
1
2
3
4
5
6
7
8
9totalcash=1000 purchase="葡萄" if(totalcash==1000 and purchase=="鳳梨"): print("環保購物袋") elif(totalcash==1000 or purchase=="鳳梨"): print("鳳梨軟糖一顆") else: print("無贈品")
CH 5|for 迴圈
5-1|迴圈介紹
另一種常見的控制流程方法是迴圈,它在程式中只被撰寫一次,但可能會重複執行數次。在 Python 中實作迴圈的方式有 for 迴圈和 while 迴圈兩種。
不過實作迴圈前,這邊先來介紹迴圈控制的指令 break
與 continue
:
- break:打破迴圈,強制跳出整個迴圈。
- continue:停止本次迴圈動作,但迴圈整體沒有結束,繼續進入下一輪。
另外還有一個比較少用的指令 pass
,它是 do nothing 的概念。我自己都拿它搭配 TODO 的註解來使用來。
測驗與練習
-
下列迴圈重要指令當中,何者是在迴圈指令當中,直接打破迴圈,使程式強制跳出迴圈?
- break
- for loop
- continue
5-2|無窮迴圈
什麼是無窮迴圈?就是讓迴圈永遠執行就叫無窮迴圈。通常發生終止條件未設定好,導致迴圈不斷執行無法停止動作,最終會導致電腦記憶體不足而發生當機的情況。
所以撰寫迴圈時,請確定程式中至少有個地方是會讓迴圈終止。不過說是這麼說啦,通常寫迴圈都會有終止條件,但偏偏中間做運算的時候出了差錯,導致無窮迴圈的產生,這種情況就真的很難抓蟲呀…
測驗與練習
-
請選出導致電腦發生「無窮迴圈」的情況
- 沒有設定好迴圈的條件,電腦不知道什麼時候要停止重複的動作
- 有設定好迴圈的條件,電腦明確知道什麼時候要停止重複的動作
5-3|for 迴圈架構:(首項、末項、差值)
在 for 迴圈的架構中會存在一個迴圈變數-初始值、條件、遞增值,使在疊代過程中能知曉執行順序。不過在課程中,初始值、條件、遞增值三個詞它使用的首項、末項、差值:
1 |
|
常見的次數控制型迴圈多會搭配 range
來函數使用,在函數中會定義首項、末項與差值的參數:
-
首項
初始值。迴圈的起始點,也就是變數 i 的起始數字,預設為 0。例如range(0,5)
等價於range(5)
。 -
末項
條件。迴圈結束的條件,在差值為正時,當變數 i 大於等於該值即會終止迴圈,因此終點值是不會執行的!舉例來說,range(0,5)
是 [0, 1, 2, 3, 4] 沒有 5。 -
差值
遞增值。每一輪迴圈結束後,變數 i 會加上此差值,作為下一輪迴圈的變數值,預設為 1。因此,range(0,5,1)
等價於range(0,5)
。
實際執行結果如下:
1 |
|
人工直譯的話其過程如下:
起始值給變數 i | 確認變數 i 是否小於末項 | 執行輸出 | 賦予差值給變數 i |
---|---|---|---|
i=0 | i<3(成立則繼續) | print(0) | i=0+1=1 |
i=1 | i<3(成立則繼續) | print(1) | i=1+1=2 |
i=2 | i<3(成立則繼續) | print(2) | i=2+1=3 |
i=3 | i<3(不成立則結束回圈) | 已跳出程式 | 已跳出程式 |
因此最終輸出:
1 |
|
在課程中提到,當迴圈的首項一定要小於末項。因為當首項大於末項且差值為1時,是沒有辦法執行該迴圈的,因為首項大於末項使終止恆成立,則無法進入迴圈。
其實這句話不完全正確,當首項大於末項且差值為正數時,的確無法執行迴圈。但差值也可為負數,這樣就會是一個遞減型的計數器,只是要稍微注意一下末項的判斷條件會與正數剛好相反。舉例來說,range(0,5,1)
是當變數大於等於 5 時,即會終止迴圈;range(5,0,-1)
則是變數小於等於 0 時,終止迴圈。
測驗與練習
-
以「range」控制迴圈執行
請設計一支程式,利用 for 迴圈,首項為 1、末項為 8、差值為 2,執行並輸出每一次迴圈中執行的結果。答:
1
2for i in range(1,8,2): print(i)
-
觀察 for 迴圈程式執行結果並完成程式改寫
承上題,若輸出規律變為如下,請觀察以下輸出規律,並利用 for 迴圈完成程式撰寫。- 每一行兩數字間有一空格,使用逗點輸出變數
- 觀察每一行兩個輸出內容之間的數學關係(加、減、乘、除、商、餘、指數)
1
2
3
41 1 3 9 5 25 7 49
答:
1
2for i in range(1,8,2): print(i,(i**2))
5-4|for 迴圈裡的流程控制
迴圈可以搭配 if 條件判斷使用,在迴圈裡面設立條件以控制迴圈。
1 |
|
結果:
1 |
|
另一個迴圈控制指令 continue
的效果如下:
1 |
|
結果:
1 |
|
不同於 break
的直接結束迴圈,continue
只是停止本次迴圈動作,繼續進入下一輪。因此會看到一個遇到 2 時,輸出就停止了;另一個則是跳過不輸出 2。
測驗與練習
-
以 break/continue 控制 for 迴圈
請改寫下列程式,新增一個 if 流程控制當控制迴圈的變數 i 為 5 時,跳過當次輸出,其餘正常輸出。答:
1
2
3
4for i in range(1,10,1): if(i==5): continue print(i)
5-5|巢狀 for 迴圈
跟巢狀 if 流程一樣,多層的 for 迴圈稱為for 巢狀迴圈。撰寫的時候除了一樣要注意縮排外,另外要注意的是變數的作用域,外層迴圈的變數會作用於內層迴圈之中,因此不同層的迴圈必需要用不同的變數去控制迴圈,否則兩者控制變數會被互相覆寫。
1 |
|
再來當一次人工直譯器:
外層變數 i | i<5? | 內層變數 j | j<3? |
---|---|---|---|
i=3 | 成立 | j=0 | 成立 |
j=1 | 成立 | ||
j=2 | 成立 | ||
j=3 | 不成立則跳出內層迴圈 |
完成內層後,回到外層重新賦值變數 i ,重新進入內層迴圈,再一次以 range(0,3,1)
執行:
外層變數 i | i<5? | 內層變數 j | j<3? |
---|---|---|---|
i=4 | 成立 | j=0 | 成立 |
j=1 | 成立 | ||
j=2 | 成立 | ||
j=3 | 不成立則跳出內層迴圈 |
最終輸出結果如下:
1 |
|
測驗與練習
-
觀察程式執行後的結果完成缺少的巢狀 for 元素
請觀察輸出範例,觀察輸出數字,並根據提示程式碼填寫遺漏的程式碼。1
2
3for i in range(0,,1): #少了末項數字該寫什麼呢? for j in range(0,,1): #少了末項數字該寫什麼呢? print(i,j)
輸出數字:
1
2
3
4
5
60 0 0 1 1 0 1 1 2 0 2 1
答:
1
2
3for i in range(0,3,1): #少了末項數字該寫什麼呢? for j in range(0,2,1): #少了末項數字該寫什麼呢? print(i,j)
CH 6|while 迴圈
6-1|當 while 迴圈條件成立時
除 for 迴圈外,另一種實作迴圈的方式是 while 迴圈,兩者在架構上及用途上大相逕庭。從英文的角度來看,while 的用法可以理解成當…的時候,放到 Python 中就是當括號的條件成立的時候:
1 |
|
不同於 for 迴圈有一個很明顯的計數器的存在,在 while 迴圈中只要判斷條件成立,就會一直執行下去,並沒有執行次數的初始限制在;因此較適合用於不確定會執行幾次,但只要條件符合就一直執行的情況。所以在寫 while 迴圈要注意迴圈終止條件的檢查,不然真的很容易搞出無窮迴圈。
1 |
|
結果:
1 |
|
測驗與練習
-
以 while 迴圈完成程式
請設計一支程式碼,觀察輸出情況並使用 while 迴圈完成程式撰寫。1
2
3
42 4 6 8
答:
1
2
3
4
5
6number=2 #設立while迴圈 while(number<10): print(number) number+=2
6-2|while 迴圈裡的流程控制
在 while 迴圈中有一種寫法是 while(True)
,它會強迫條件判斷一直成立,此時必須搭配 break
來對迴圈進行控制,否則絕對是無窮迴圈 XDDD
1 |
|
結果:
1 |
|
沒有認真去看過 Python 的原始碼,不過就行為來說 while
後面的判斷式跟 bool()
的行為一樣,有興趣的可以去看看上次踩的坑。while
只有在下列情況回傳 False 而已,其他狀況都是回傳 True:
- 傳入 False 值。
- 傳入 None。
- 傳入空值,如:空陣列、空列表、空字典、空字串…等。
- 傳入數字 0 ,資料型態為整數或浮點數都算。
- 傳入物件類別具有
__bool __
或__len()__
,且其回傳值為 False 或 0。
所以如果傳入其他的情況,會被視為 while(True)
繼續向下執行:
1 |
|
結果:
1 |
|
測驗與練習
-
使用 if 流程控制 while 迴圈
請完成下列程式,有一變數 a=5,使用 while(True),在迴圈內每完成一次就讓 a+1,當 a 大於 10 時,則停止迴圈,輸出當下變數 a 的數值。1
2
3
4
5
6
75 6 7 8 9 10 11
答:
1
2
3
4
5
6
7
8
9
10a=5 #設立while迴圈 while(True): #判斷是否停止迴圈「continue/break」 if a > 10: break print(a) a += 1 #變動變數a控制迴圈執行狀況
題目有點問題,在它要求的輸出結果中有 11,但按文字敘述 a 大於 10 時停止迴圈,不應該列出 11 才對,而它批改的答案中也果然沒有 11。
6-3|while 運用
基本上,上述所提到的流程控制,都可以相互使用,只要邏輯成立,就可以使程式順利執行。
讓我們繼續殘害媽媽的錢包:
- 如果數學考試考了 100 分,就會得到 10 張「獎勵雞排兌換卷」
- 若數學分數介於 90~100 之間(不包含 100 分),就會得到 3 張「獎勵雞排兌換卷」
- 若低於 90 分,則「無獎勵」
1
2
3
4
5
6
7
8
9
10
11
12math_score=90 if(math_score==100): number=0 while(number<10): print(number+1,"獎勵雞排兌換卷") number+=1 elif(math_score>=90): number=0 for number in range(0,3,1): print(number+1,"獎勵雞排兌換卷") else: print("無獎勵")
測驗與練習
-
while 迴圈應用練習
請設計一支程式,使用 while 迴圈執行 20 以內(不含 20)的偶數相加,並以變數 sum 儲存總和,意即 1~19 的所有偶數相加(2、4、8、10、12、14、16、18)。- 偶數定義:可被2整除(被2除後餘數為0)
- 和為 90
答:
1
2
3
4
5
6
7
8
9
10
11
12a=0 sum=0 #設立「while迴圈」 while(a<20): if(a%2==0): #若a為偶數 #sum加總a sum += a #變數a做更動以控制while迴圈 a += 1 print(sum)
CH 7|資料型態:串列
7-1|串列的架構
串列(list)是一種容器資料型別,可以用來儲存一連串有順序性的元素。例如我們要儲存資料 「hi」、「你好」、「Bonjour」、「こんにちは」、「15」,一共五項資料,換成串列儲存就可以變為:
1 |
|
結果:
1 |
|
測驗與練習
-
使用中括號完成串列
請設計一支程式,新增一個串列 fruit 儲存下列水果名稱,並輸出一整個串列。1
"apple","orange","pineapple","grape"
答:
1
2fruit=["apple","orange","pineapple","grape"] #想想看少了什麼串列符號 print(fruit) #輸出一整個串列
7-2|串列的長度
串列長度有多長,取決於串列內部總共有多少筆資料。在 Python 中有提供一函數能快速回傳串列長度:
1 |
|
還是剛剛的串列例子:
1 |
|
在串列中一共有 5 筆資料,因此串列長度輸出為 5:
1 |
|
測驗與練習
-
使用 len() 輸出串列長度
承上單元題目,請輸出該串列 fruit 的長度,不可以用print(4)
直接輸出。答:
1
2fruit=["apple","orange","pineapple","grape"] print(len(fruit))#輸出該串列長度
這題目可以!直接輸出 4,害我想到翻轉二元樹的笑話 XDDD
7-3|獲取取串列資料
因串列中儲存的資料具備順序性,因此若需要獲取串列中的資料時,可以使用索引值來提取,第一筆資料由 0
開始,以此類推,直到最後一筆。
串列中的索引值(圖片來源: Codefree - Python 進階篇)
針對最後一筆資料,除可使用 總長度-1
來表示外,也可以直接使用 -1
來讀取。
1 |
|
結果:
1 |
|
如果存取了超過串列長度的索引,會而引起的 IndexError:
1 |
|
結果:
1 |
|
測驗與練習
-
透過串列索引值讀取串列資料
承上單元題目,請輸出串列 fruit 第一個存入的資料。答:
1
2fruit=["apple","orange","pineapple","grape"] print(fruit[0])
7-4|新增串列的資料
如要新增資料到串列中,存在 3 種方法:
-
.append(新增資料)
:新增資料至串列最後一筆1
2
3
4mylist=["hi","你好","Bonjour","こんにちは",15] mylist.append("안녕") print(mylist)
結果:
1
['hi', '你好', 'Bonjour', 'こんにちは', 15, '안녕']
-
.insert(指定位置,新增資料)
:新增資料至串列指定位置1
2
3
4mylist=["hi","你好","Bonjour","こんにちは",15] mylist.insert(0,"Olá") #指定把資料放到第0個位子 print(mylist)
結果:
1
['Olá', 'hi', '你好', 'Bonjour', 'こんにちは', 15]
-
.extend([多筆資料])
:新增多筆資料至串列後方1
2
3
4mylist=["hi","你好","Bonjour","こんにちは",15] mylist.extend(["Olá","안녕"]) print(mylist)
結果:
1
['hi', '你好', 'Bonjour', 'こんにちは', 15, 'Olá', '안녕']
測驗與練習
-
新增資料值至串列最後
請使用「新增資料值至串列最後」的方法,新增新的資料「peach」至串列 fruit 最後,並輸出一整個串列。1
['apple', 'orange', 'pineapple', 'grape', 'peach']
答:
1
2
3fruit=["apple","orange","pineapple","grape"] fruit.append("peach") print(fruit)
-
新增資料值至串列指定位置
承上題,請使用新增多筆資料值至串列後方的方法,新增新的資料「tomato」、「lemon」至串列 fruit 最後,並輸出一整個串列。1
['guava', 'apple', 'orange', 'pineapple', 'grape', 'peach']
答:
1
2
3
4fruit=["apple","orange","pineapple","grape"] fruit.append("peach") fruit.insert(0,"guava") print(fruit)
- 挑戰3. 新增多筆資料值至串列後方
承上題,請使用「新增多筆資料值至串列後方」的方法,新增新的資料「tomato」、「lemon」至串列fruit最後,並輸出一整個串列。1
['guava', 'apple', 'orange', 'pineapple', 'grape', 'peach', 'tomato', 'lemon']
答:
1
2
3
4
5fruit=["apple","orange","pineapple","grape"] fruit.append("peach") fruit.insert(0,"guava") fruit.extend(["tomato", "lemon"]) print(fruit)
7-5|刪除串列的資料
有新增就有刪除!不過刪除串列資料的方法則只有 2 種:
-
del 串列變數名稱[欲刪除資料的位置]
:刪除串列特定索引值資料1
2
3
4mylist=["hi","你好","Bonjour","こんにちは",15] del mylist[0] print(mylist)
結果:
1
2['你好', 'Bonjour', 'こんにちは', 15] #刪除完資料後,會自動遞補資料,因此索引值0為你好
-
.remove(資料內容)
:刪除串列內指定資料
若存在相同資料時,會砍最左邊的,也就是砍索引值小的。1
2
3mylist=["hi","你好","Bonjour","こんにちは",15,"こんにちは"] mylist.remove("こんにちは") print(mylist)
結果:
1
['hi', '你好', 'Bonjour', 15, 'こんにちは']
如果指定刪除的資料不在串列時,會得到 ValueError:
1 |
|
結果:
1 |
|
測驗與練習
-
指定刪除串列的資料
請利用串列刪除方法,刪除串列 fruit 最後一個資料內容。請使用程式找出最後一個位子,勿輸出del fruit[3]
1
['apple', 'orange', 'pineapple']
答:
1
2
3fruit=["apple","orange","pineapple","grape"] del fruit[len(fruit)-1] print(fruit)
-
刪除串列內特定資料值
承上題,請刪除串列 fruit 中資料名稱為「pineapple」的資料。1
['apple', 'orange']
答:
1
2
3
4fruit=["apple","orange","pineapple","grape"] del fruit[len(fruit)-1] fruit.remove("pineapple") print(fruit)
7-6|串列綜合運用
請設計一支程式,運用前面章節所學到的串列方法,完成下列實作練習規定:
-
使用新增串列資料方法新增資料
運用新增方法新增資料至串列 country 中,資料值為:「Japan」,「India」,「Algeria」,「Brazil」,最後輸出該串列。答:
1
2
3
4country=[] #1 country.extend(['Japan', 'India', 'Algeria', 'Brazil']) print(country)
-
將「該串列長度」資料放至特定位子
計算串列 country 長度,並將結果新增至串列最一開始的位子,輸出整個串列內容。答:
1
2
3
4
5
6
7country=[] #1 country.extend(['Japan', 'India', 'Algeria', 'Brazil']) #2 country.insert(0,len(country)) print(country)
-
刪除串列規定資料值
刪除串列最後一個資料值,並輸出該串列。 答:1
2
3
4
5
6
7
8
9country=[] #1 country.extend(['Japan', 'India', 'Algeria', 'Brazil']) #2 country.insert(0,len(country)) #3 del country[len(country)-1] print(country)
-
修改串列資料值
修改串列索引值第 0 位的資料內容,讀取第 0 位資料值後減 1,並輸出該串列。答:
1
2
3
4
5
6
7
8
9
10
11country=[] #1 country.extend(['Japan', 'India', 'Algeria', 'Brazil']) #2 country.insert(0,len(country)) #3 del country[len(country)-1] #4 country[0] -= 1 print(country)
CH 8|資料型態:字典
8-1|字典架構
字典是 Python 所提供的另一種容器資料型別,在儲存資料時會以鍵(key)和值(value)組合。其中 key 值具備唯一性,如果存在相同 key 值,後面會蓋掉前面宣告;但反之 value 值並不具備該特性。因此有可能會出現一個 key 值對應一個 value 值,但 value 值卻有可能對應多個 key 值。
1 |
|
結果:
1 |
|
與串列不同的是,字典並沒有固定排序,因此每次執行輸出時的資料順序各不相同;因此,字典通常會用在不在意排順序的資料上。
格式上類似 JSON ,兩者都是種結構化資料,皆是利用 key 作為分類關鍵字,將儲存內資料依照各定方式進行分類,這些資料可以是字串、數字、布林、容器資料型別…等資料格式。
- List(串列):一個值可變、可重複、存放有順序性的資料結構。
- Tuple(元組):一個值不可變、可重複、存放有順序性的資料結構。
- Set(集合):一個值可變、不可重複、存放沒有順序性的資料結構。
- Dictionary(字典):一個值可變、可重複、存放沒有順序性且使用唯一 Key的資料結構。
測驗與練習
-
以字典方式儲存資料
請設計一支程式儲存關於「人類」的資料值,字典名稱為「people」分類與資料為下,請輸出整個字典內容。資料內容:
- name :人類
- variety :white,black,yellow
- gender :male,female
- age :0,12,18,45,60
答:
1
2
3
4
5
6
7people={ "name":"人類", "variety":["white","black","yellow"], "gender":["male","female"], "age":[0,12,18,45,60] } print(people)
8-2|字典取資料值
因為字典不具備順序性,因此不存在索引值。若要提取字典中的資料,則需透過直接指定 key 的方式,來讀取相對應的 value。
1 |
|
結果:
1 |
|
測驗與練習
-
讀取字典資料值
承上單元題目,請輸出鍵(key)為「gender」的資料值。答:
1
2
3
4
5
6
7
8people={ "name":"人類", "variety":["white","black","yellow"], "gender":["male","female"], "age":[0,12,18,45,60] } print(people["gender"])
8-3|字典新增資料值
也因為它不具備順序性,因此在新增的時候只需要透過新增 key 並賦其 value 值的方式即可。
1 |
|
結果:
1 |
|
測驗與練習
-
新增資料值至字典中儲存
承上單元題目,請運用字典新增方式新增下列 key 與 value,並輸出一整個字典內容。1
single:["yes","no"]
答:
1
2
3
4
5
6
7
8
9people={ "name":"人類", "variety":["white","black","yellow"], "gender":["male","female"], "age":[0,12,18,45,60] } people["single"]=["yes","no"] print(people)
8-4|字典刪除資料值
刪除字典內的資料有 2 種方法,一種是直接呼叫 del,將它從字典中刪除:
1 |
|
結果:
1 |
|
另一種則是使用 pop
,將該值從字典中彈出。既然是彈出,就會有回傳值:
1 |
|
結果:
1 |
|
測驗與練習
-
刪除字典資料值
請刪除鍵 key 為「age」的值,並輸出一整個字典與「age」返回之值。答:
1
2
3
4
5
6
7
8
9
10people={ "name":"人類", "variety":["white","black","yellow"], "gender":["male","female"], "age":[0,12,18,45,60] } age=people.pop("age") print(people) print(age)
CH 9|函數 function
9-1|function 設定格式架構
在寫程式碼的一個重要的觀念是 Don’t Repeat Yourself,也就是要儘量避免相同的程式碼重複出現,這會降低可讀性很低外,並讓你維護的直升地獄難度。所以此時會進行封裝,達到程式碼的重用。
在 Python 中,若我們要封裝一段程式邏輯便於其後的使用時,我們會 function 函式來進行。而函式又分成內建函式與自定義函式 2 種。
例如說上一章節所使用 len()
、計算總和 sum()
、排序 sorted()
、取最大值的 max()
…等,這些都是 Python 中常用的內建函式,可以直接拿來使用:
1 |
|
結果:
1 |
|
另一種則是我們定義的函式,這可以實做我們想要的邏輯。這邊有個重要的關鍵字 def
,用來定義即將實做的函式:
定義即將實做的函式(圖片來源: Wen Chang|Medium)
測驗與練習
-
Python 擁有眾多函式提供給開發者使用,但若沒有自己想要的函式,可以根據自己要求客製化函式使用,稱作「自定義函式」,而自定義函式有一個很重要的關鍵字,請問為何?
-
sorted
-
sum()
-
def
-
9-2|在 function 內直接輸出
課程這邊依照是否有回傳值分開講解,這一個章節會先教在函式內直接輸出的方法:
1 |
|
結果:
1 |
|
呼叫自定義函式(圖片來源: Codefree - Python 進階篇)
測驗與練習
-
自定義函式-判斷閏年
請完成閏年判斷的自定義函式,根據閏年條件將程式完成,於函式內直接輸出是否為函式的結果。- 條件1:能被 100 整除且能被 400 整除
- 條件2:不能被 100 整除且能被 4 整除
答:
1
2
3
4
5
6
7
8def checkyear(year): if((year%100==0 and year%400==0) or (year%100!=0 and year%4==0)): print(year,"是閏年") else: print(year,"不是閏年") #完成呼叫自定義函式,帶入參數2021 checkyear(2021)
9-3|function 結束後回傳資料值
承上單元題目,一樣是判斷是否為偶數的程式,若使用函式的回傳值功能,程式將改寫為以下:
1 |
|
結果:
1 |
|
呼叫自定義函式-回傳值(圖片來源: Codefree - Python 進階篇)
測驗與練習
-
自定義函式-透過「回傳值」方法判斷閏年
承上單元題目,請將閏年自定義函式改為回傳值(return)方式。答:
1
2
3
4
5
6
7def rCheckyear(year): if((year%100==0 and year%400==0) or (year%100!=0 and year%4==0)): return("是閏年") else: return("不是閏年") year=2021 print(year,rCheckyear(year))
9-4|全域變數與區域變數
呼叫自定義函式時,需要注意變數的擺放位置,擺放位置會影響變數的作用域。若變數擺於函式的外面,則代表為全域變數;反之,則代表為區域變數。
全域變數運用的範圍需特別注意,它在函式內可被讀取,但若需要做其他的運算,則需將其在函式中命定 global
;若沒有命定,則程式無法進行運算並且會拋出錯誤:
1 |
|
結果:
1 |
|
測驗與練習
-
在程式當中的設定在自定義函式以外就稱作全域變數,若需要在自定義函式內使用全域變數做運算,則需要多執行什麼動作?
- 將變數放在函數外
- 在自定義函式中宣告「global」
- 電腦自己會知道哪些是全域變數
CH 10|物件導向程式概念
10-1|什麼是物件?
物件導向程式設計(Object-oriented programming,OOP)有三大特色:封裝(IEncapsulation)、繼承(Inheritance)、多型(Polymorphism)。其優點在於程式比較有架構且可重複使用。
舉例來說,現實生活當中的人、貓、狗、椅子、桌子…等都可以稱作物件。而將這些資料抽象化則成類別,這些類別是由屬性(attributes) 和 方法(method) 所構成組成,若當我們將類別實例化時,就成了物件。
我們以貓為例子,在類別中我們會定義它的資料:
- 屬性(attributes):貓毛的顏色、尾巴的長短…等等
- 方法(method):會吃、會叫
測驗與練習
-
類別(Class)中又包含哪些組成?
- 類別(class)和方法(method)
- 屬性(attribute)和方法(method)
-
類別(class)和物件(object)
-
關於物件導向程式設計特色,以下何者並非為特色?
- 繼承
- 屬性
- 封裝
- 多型
10-2|物件(Object)與類別(Class)之間關係與使用
在創立類別時,需在程式當中寫關鍵字 class
後,並在其後接上類別名稱。習慣上,類別的命名會採用大駝峰式命名法:
1 |
|
結果:
1 |
|
在將類別實例化時,會直接呼叫類別名稱,並其賦值給指定變數,這就成了一個物件。
測驗與練習
-
使用類別(Class)
有一支程式已有類別 Dog ,請試著使用該類別。 有一支程式已有類別 Dog ,請試著使用該類別。1
2class Dog: print("這是狗")
答:
1
2
3
4
5class Dog: print("這是狗") #呼叫類別 dog = Dog()
-
在創造類別(Class)時需注意名字的第一個字要特別做什麼動作?
- 第一個字母需大寫
- 最後一個字母需小寫
- 第一個字母需小寫
雖然這是公認的命名規則,但實際上它只是屬於命名潛規則,即便用小寫也不會跳 error。問我怎麼知道?我剛剛去嘗試過了!
類別命名字首不為大寫
10-3|class 與 method 的關係
在前面章節中有講解到,類別當中有包含屬性和方法,而 Python 中會使用 __init__()
來設定初始屬性資料。
1 |
|
結果:
1 |
|
而方法的定義,則與前一節的 function 定義一樣:
1 |
|
結果:
1 |
|
測驗與練習
-
改寫範例程式以創造新的實例
請根據提供的範例程式,創造新的實例變數 english,並說「Hello~」。答:
1
2
3
4
5
6
7
8class People: def __init__(self, voice): self.voice = voice def speak(self): return "Hello~" english = People("你好!").speak() print(english)
10-4|繼承
物件導向程式觀念之中,最常運用到的就是繼承關係。在繼承關係中,會出現父類別與子類別兩個角色,子類別會承自父類別的程式架構,子類別再根據自身需求與特性進行修改。
以下圖形來觀察繼承觀念:
串列中的索引值(圖片來源: Codefree - Python 進階篇)
結果:
1 |
|
測驗與練習
-
物件繼承
請設計一支程式,設立一個子類別(Class)為 Cat 去繼承父類別 Animal 的內容,並在子類別中設立一個方法「tail」輸出「有尾巴」。答:
1
2
3
4
5
6
7
8
9
10
11
12class Animal(): def __init__(self,voice): self.voice=voice print(self.voice) class Cat(Animal): def tail(self): print("有尾巴") tomcat=Cat("喵~") tomcat.tail()
課程內容
更新紀錄
最後更新日期:2022-07-05
- 2022-07-05 發布
- 2022-07-05 完稿
- 2022-06-29 起稿