01

電腦科學在研究什麼

電腦科學是研究問題與解法的學問;演算法是有限步驟的解法,而有些問題根本無解。

先讀原文段落,旁邊就是白話

這是一本英文書。左邊放原文、右邊放白話導讀——你既讀得懂,也順手碰了原文。

原文 · 電腦科學在研究什麼 CHAPTER ONE INTRODUCTION 1. 1 Objectives • To review the ideas of computer science, programming, and problem-solving. • To understand abstraction and the role it plays in the problem-solving process. • To understand and implement the notion of an abstract data type.
白話導讀

電腦科學是研究問題與解法的學問;演算法是有限步驟的解法,而有些問題根本無解。

問題、演算法與可計算性

電腦科學是研究問題與解法的學問;演算法是有限步驟的解法,而有些問題根本無解。

STEP 1

深度探秘

電腦科學其實不是『學電腦』

名字騙了你

「電腦科學 (Computer Science)」這個名字其實很容易誤導人。它不是研究電腦這台機器本身的學問,電腦只是過程中很重要的工具而已。

電腦科學是研究問題 (problems)解決問題的過程 (problem-solving),以及這個過程產出的解法 (solutions) 的學問。

實例。">演算法 = 解法

面對一個問題,電腦科學家的目標是發展出一個 演算法 (algorithm)

  • 一份一步一步的指令清單
  • 能解決這個問題的任何一個實例 (instance)
  • 而且是有限的過程(照著做一定會停、會得到答案)

換句話說,演算法就是解法本身,它跟用哪台機器、哪種程式語言無關。

有些問題根本無解

要小心一件事:不是所有問題都有解法。有些問題已被證明不存在任何演算法可以解它。所以更完整的定義是:電腦科學同時研究『有解的問題』與『無解的問題』。

💡
關鍵

電腦科學研究的是問題與解法,演算法就是解法,電腦只是工具。

STEP 2

生活妙喻

演算法就像一份食譜

食譜與料理

問題想成「我想吃一盤蛋炒飯」,那麼演算法就是那份食譜

  • 食譜有明確的步驟:先打蛋、熱油、下飯、翻炒、調味、起鍋。
  • 它能應付任何一鍋飯(不同分量、不同鍋子)——這就是『解決任何實例』。
  • 它一定會結束:照著做完就有飯吃,不會永遠炒下去。

而真正的爐子、鍋子就像電腦——只是讓食譜得以執行的工具。同一份食譜換一個廚房也能做出同樣的菜。

有些料理做不出來

如果有人要你『煮出一鍋永遠吃不完又永遠是熱的飯』,再厲害的食譜也寫不出來——這就對應到『無解的問題』。電腦科學家的一部分工作,就是分辨哪些『料理』根本做不出來。

💡
關鍵

演算法像食譜:明確步驟、能應付任何實例、保證會結束,而電腦只是廚房。

STEP 3

可計算性

computable 是什麼意思

可計算 (computable)

當一個問題存在能解它的演算法時,我們說這個問題是可計算的 (computable)。於是電腦科學還有另一種定義方式:

電腦科學是研究『可計算與不可計算問題』、研究『演算法存在與不存在』的學問。

注意:在這整個定義裡,『電腦』這個詞根本沒出現過——因為解法與機器是獨立的

三種問題,三種命運

flowchart TD
    A[一個問題] --> B{存在演算法嗎}
    B -->|存在且夠快| C[可計算且實用]
    B -->|存在但太慢| D[難解 intractable]
    B -->|不存在| E[無解問題]

學會分辨這三種,是後面學分析演算法的重要起點:有解、無解、以及『有解但代價太高』。

💡
關鍵

問題若存在解它的演算法就是可計算的;解法獨立於機器之外。

🔆
生活妙喻:演算法 ≈ 食譜

食譜用明確且有限的步驟,能料理任何一鍋食材,正如演算法用有限步驟解決問題的任何實例。

🔆
生活妙喻:電腦 ≈ 廚房的爐子與鍋子

爐具只是讓食譜得以執行的工具,同一份食譜換廚房也能做菜,正如解法獨立於機器之外。

本節字彙

演算法 (algorithm)
一份一步一步、有限的指令清單,照著做就能解決某類問題的任何實例。
🧠 把它想成『解法的食譜』:步驟明確、保證做得完。
可計算 (computable)
若一個問題存在能解它的演算法,這個問題就是可計算的。
🧠 computable = 有食譜可煮;找不到食譜就不可計算。
實例 (instance)
同一類問題的某個具體版本,例如『排序這串特定數字』是『排序問題』的一個實例。
🧠 問題是『題型』,實例是『這一題』。
依本節的定義,下列哪一句最貼近『電腦科學』真正研究的核心?
下列哪個敘述『不』符合演算法的特性?
某問題目前找不到任何演算法可以解它,且已被證明這樣的演算法不存在。依本節說法,這代表什麼?

抽象化:邏輯觀點與實體觀點

用開車與數學模組的比喻,分清楚『介面』與『底層細節』,理解程序抽象化與黑盒子概念。

STEP 1

深度探秘

把『怎麼用』和『怎麼做』分開

抽象化 (abstraction)

解決問題時,複雜度常常讓人迷失在細節裡。抽象化是電腦科學最重要的武器之一,它讓我們把同一件事拆成兩種觀點:

  • 邏輯觀點 (logical perspective):使用者怎麼用這個東西。
  • 實體觀點 (physical perspective):底層怎麼運作的所有細節。

介面是兩者的橋

連接使用者與底層複雜度的橋樑,就是介面 (interface)。只要你懂介面怎麼用,就不需要知道內部細節。

使用抽象的人有時稱為客戶 (client)

觀點 是誰 關心什麼
邏輯觀點 使用者 / 客戶 介面怎麼用、能做什麼
實體觀點 實作者 / 維護者 內部如何運作的細節
💡
關鍵

抽象化把『邏輯觀點(怎麼用)』與『實體觀點(怎麼做)』分開,介面是兩者的橋。

STEP 2

生活妙喻

開車的人 vs. 修車的技師

同一台車,兩種眼光

想想你今天開的那台車:

  • 身為駕駛,你只需要轉鑰匙、踩油門、打方向盤——你看到的是車子的邏輯觀點,用設計者提供的功能把自己從 A 載到 B。這些功能就是車子的介面
  • 技師看到的是實體觀點:引擎怎麼運轉、變速箱怎麼換檔、溫度怎麼控制——也就是『引擎蓋底下』的細節。

共通點

兩個角色的共通點是:駕駛(客戶)不需要懂引擎蓋底下的事,只要會用介面就好

flowchart LR
    A[駕駛 客戶] -->|透過介面 油門方向盤| B[車子]
    B -.隱藏.-> C[引擎 變速箱 等實體細節]
💡
關鍵

駕駛只需懂介面(邏輯觀點),技師才需懂引擎蓋底下(實體觀點)。

STEP 3

實用超能力

程序抽象化與黑盒子

數學模組的例子

在 Python 裡呼叫平方根,就是一個程序抽象化 (procedural abstraction) 的範例:

>>> import math
>>> math.sqrt(16)
4.0

我們不知道它內部到底怎麼算平方根,但我們知道:

  • 函式叫什麼名字(sqrt
  • 要餵它什麼(參數 16)
  • 它會回傳什麼(4.0)

黑盒子 (black box)

這就是所謂的黑盒子觀點:只描述介面(名稱、參數、回傳值),把細節藏在裡面。

這是你未來寫程式的超能力:把複雜的東西包成一個你信任、會用就好的盒子,專心去解更大的問題。

💡
關鍵

程序抽象化讓你像用黑盒子一樣:只需知道名稱、參數、回傳值就能使用。

🔆
生活妙喻:邏輯觀點 vs. 實體觀點 ≈ 開車的駕駛 vs. 修車的技師

駕駛只透過油門方向盤等介面用車(邏輯觀點),技師才需要懂引擎蓋底下的運作(實體觀點)。

🔆
生活妙喻:程序抽象化 ≈ 黑盒子

math.sqrt 像個黑盒子,你只看得到輸入與輸出,看不到也不需要看到內部如何運算。

本節字彙

抽象化 (abstraction)
把『怎麼用』與『怎麼做』分開的思考方式,讓人專注於大方向而不迷失在細節裡。
🧠 抽象化 = 只看『要做什麼』,先不管『怎麼做到』。
介面 (interface)
使用者與底層複雜實作之間溝通的方式,例如函式的名稱、參數與回傳值。
🧠 介面就是『使用說明書』,懂它就會用,不必拆開機器。
程序抽象化 (procedural abstraction)
把一段運算包成函式,使用者只需知道名稱、參數與回傳值,不必知道內部實作。
🧠 把運算裝進黑盒子,貼上『名稱+輸入+輸出』的標籤。
你呼叫 `math.sqrt(25)` 得到 5.0,卻完全不知道它內部用什麼方法算出來的。這最能說明哪個觀念?
用『駕駛』與『技師』的比喻來看,下列對應何者正確?
一個設計良好的『介面』最重要的價值是什麼?
02

為什麼要學資料結構與演算法

ADT 是資料的邏輯描述(封裝與資訊隱藏),資料結構則是它的實作;兩者分離帶來實作獨立性。

先讀原文段落,旁邊就是白話

這是一本英文書。左邊放原文、右邊放白話導讀——你既讀得懂,也順手碰了原文。

原文 · 為什麼要學資料結構與演算法 ADT, is a logical description of how we view the data and the operations that are allowed without regard to how they will be implemented. This means that we are concerned only with what the data is representing and not with how it will eventually be constructed. By providing this level of abstraction, we are creating an encapsulation around the data. The idea is that by encapsulating the details of the implementation, we are hiding them from the user’s view.
白話導讀

ADT 是資料的邏輯描述(封裝與資訊隱藏),資料結構則是它的實作;兩者分離帶來實作獨立性。

抽象資料型別 ADT 與資料結構

ADT 是資料的邏輯描述(封裝與資訊隱藏),資料結構則是它的實作;兩者分離帶來實作獨立性。

STEP 1

深度探秘

ADT 是『資料的黑盒子』

從程序抽象化到資料抽象化

前面看到的程序抽象化是『隱藏一個函式的細節』;現在我們把同樣的想法用在資料上,這叫資料抽象化 (data abstraction)

抽象資料型別 (Abstract Data Type, 簡稱 ADT) 是:

對『我們如何看待這份資料』以及『允許對它做哪些操作』的邏輯描述,完全不管它將來怎麼被實作

換句話說,ADT 只關心資料代表什麼、能做什麼,不關心怎麼蓋出來

封裝與資訊隱藏

  • 封裝 (encapsulation):在資料外圍包一層殼,使用者只透過殼上的操作來互動。
  • 資訊隱藏 (information hiding):把實作細節藏在殼裡,使用者看不到。
flowchart TD
    U[使用者 client] -->|只用介面操作| S[ADT 外殼 介面]
    S -.資訊隱藏.-> I[實作 資料結構]
💡
關鍵

ADT 是資料的邏輯描述:只說『是什麼、能做什麼』,用封裝與資訊隱藏把細節藏起來。

STEP 2

生活妙喻

點餐單 vs. 廚房

餐廳的菜單與廚房

ADT 想成餐廳的菜單,把資料結構想成廚房

  • 菜單 (ADT) 告訴你:有哪些餐點、你可以點什麼、會端出什麼。這是『邏輯描述』。
  • 廚房 (資料結構) 才是真正用鍋碗瓢盆把菜做出來的地方,那是『實體實作』。

你身為客人(client),只看菜單點餐,完全不需要知道廚房怎麼運作——這就是資訊隱藏。

換廚房,不換菜單

最妙的是:餐廳今天換了一批新廚具、改了烹調流程(換掉資料結構的實作),只要菜單不變,你點餐的方式完全不用改。這就是接下來要講的『實作獨立性』。

💡
關鍵

ADT 像菜單(你怎麼點、會得到什麼),資料結構像廚房(實際怎麼做出來)。

STEP 3

實用超能力

資料結構與實作獨立性

資料結構 = ADT 的實作

資料結構 (data structure) 就是 ADT 的實作:它用程式語言的建構與基本型別,提供資料的實體觀點

概念 對應觀點 比喻
ADT 邏輯觀點(是什麼、能做什麼) 菜單
資料結構 實體觀點(怎麼蓋出來) 廚房

實作獨立性 (implementation independence)

一個 ADT 通常有很多種實作方式。把邏輯與實體分開,帶來一個超能力:

程式設計師可以換掉內部實作的細節(換一種更快的資料結構),而完全不影響使用者與資料互動的方式。

這讓使用者能持續專注在解題本身,而不被底層細節綁架。

💡
關鍵

資料結構是 ADT 的實作;分離兩者帶來實作獨立性,可換實作而不影響使用者。

🔆
生活妙喻:ADT 與資料結構的關係 ≈ 餐廳菜單與廚房

菜單(ADT)描述你能點什麼、會得到什麼;廚房(資料結構)才是真正做菜的地方。換廚房不換菜單,點餐方式照舊。

🔆
生活妙喻:資訊隱藏 ≈ 廚房門上的『非工作人員請勿進入』

客人看不到也不需要看到廚房內部,正如資訊隱藏把實作細節擋在介面之外。

本節字彙

抽象資料型別 (ADT)
對資料『是什麼、允許哪些操作』的邏輯描述,與將來如何實作無關。
🧠 ADT = 菜單:只列『你能點什麼』,不寫『廚房怎麼煮』。
資料結構 (data structure)
ADT 的實作,用程式語言的建構與基本型別提供資料的實體觀點。
🧠 資料結構 = 廚房:真正把菜做出來的地方。
資訊隱藏 (information hiding)
把實作細節封裝在介面後面,讓使用者看不到也不需要知道。
🧠 細節關進廚房,客人只看得到菜單。
實作獨立性 (implementation independence)
使用者透過 ADT 介面互動,因此可以替換底層實作而不影響使用方式。
🧠 換廚房不換菜單,客人點餐照舊。
下列哪一句最精準描述『抽象資料型別 (ADT)』?
用菜單與廚房的比喻,『資料結構』對應的是哪一個,為什麼?
團隊把某 ADT 底層的實作從一種資料結構換成另一種更快的,使用者的程式碼卻完全不用改。這展現了什麼?

為什麼要研究演算法

同一個問題常有多種解法,學會分析與比較演算法的好壞,並認識難解 (intractable) 問題與取捨。

STEP 1

深度探秘

同一題,多種解法

解法不只一種

電腦科學家是從經驗中學習的:看別人解題、自己動手解題,累積出模式辨識 (pattern recognition) 的能力,下次遇到類似問題就能更快上手。

關鍵體悟是:同一個問題往往有很多不同的演算法

以前面的 sqrt 為例,計算平方根可以有很多種實作方式:

  • 有的演算法用掉少很多的資源。
  • 有的演算法可能要花10 倍的時間才回傳結果。

兩個都『能跑、都對』,但其中一個顯然更好

我們需要一把尺

既然解法不只一種,我們就需要一套方法來比較與評估它們的好壞。

💡
關鍵

同一問題常有多種演算法,效率可能天差地遠,所以我們需要方法來比較好壞。

STEP 2

生活妙喻

從家到公司的多條路線

導航 App 的多條路線

『從家到公司』是一個問題,而每一條路線都是一個演算法:

  • 走高速公路:里程長但通常快。
  • 走市區小路:里程短但一堆紅綠燈。
  • 走山路:風景好但耗油又耗時。

每一條路線都能到達公司(都正確),但成本(時間、油錢)差很多。導航 App 做的事,就是幫你比較與評估這些路線。

公平的比較

更重要的是:我們想比較的是路線本身的特性(距離、紅綠燈數),而不是你今天開的是哪台車或路上塞不塞——也就是要排除掉與『解法本身』無關的干擾因素。

分析演算法,就是只看演算法本身的特性來比較,不被『程式怎麼寫』或『用哪台機器』影響。

💡
關鍵

多條路線都能到達,但成本不同;分析演算法就是比較路線本身,而非車子或路況。

STEP 3

實用超能力

難解問題與取捨

難解 (intractable) 問題

最糟的情況是:問題有解法,但這個解法需要不切實際的大量時間或資源才能跑完。這種問題稱為難解 (intractable)

所以我們要能分辨三種狀況:

flowchart TD
    P[一個問題] --> A{有演算法嗎}
    A -->|有且實用| OK[可有效解決]
    A -->|有但太耗資源| HARD[難解 intractable]
    A -->|沒有| NO[無解]

取捨 (trade-offs)

真實世界裡常有取捨要做:

  • 一個演算法跑得快,但很吃記憶體。
  • 另一個省記憶體,但比較慢。

身為解題者,除了會解問題,還要懂解法評估技術:找到一個解法之後,再判斷它是不是一個『好』解法——這件事你會一遍又一遍地做。

💡
關鍵

要分辨有解、無解與難解三種問題,並學會在時間與空間等取捨間做評估。

🔆
生活妙喻:比較不同演算法 ≈ 導航 App 比較多條路線

從家到公司有很多路線,都能到達但成本不同;分析演算法就是比較路線本身的特性,而非車子或路況。

🔆
生活妙喻:難解問題 ≈ 理論上能走但要走一萬年的路

難解問題有解法,但需要不切實際的時間,就像一條理論存在卻久到沒人走得完的路。

本節字彙

演算法分析 (analysis)
只根據演算法本身的特性(如所需時間、記憶體)來比較不同解法的好壞,不受程式寫法或機器影響。
🧠 比的是『路線本身』,不是『你的車』。
難解 (intractable)
問題雖有演算法可解,但需要不切實際的大量時間或資源才能完成。
🧠 走得到,但要走一萬年的那種路。
取捨 (trade-off)
在不同目標(如速度與記憶體)之間做出權衡的選擇,魚與熊掌常不可兼得。
🧠 快一點通常就吃記憶體一點,反之亦然。
兩個演算法都能正確算出平方根,但一個比另一個慢 10 倍。本節想傳達的主要訊息是?
『演算法分析』強調只看演算法本身的特性來比較。用導航比喻,這對應到?
某問題存在演算法,但跑完需要數百萬年。依本節術語,這類問題稱為?
03

Python 資料型別大複習

int、float、bool 與運算子,以及『變數持有的是資料的參考』這個關鍵觀念。

先讀原文段落,旁邊就是白話

這是一本英文書。左邊放原文、右邊放白話導讀——你既讀得懂,也順手碰了原文。

原文 · Python 資料型別大複習 ond prints the result of some simple processing based on the string that is provided. user_name = input("Please enter your name ") print("Your name in all capitals is",user_name. upper(), "and has length", len(user_name)) It is important to note that the value returned from the input function will be a string representing the exact characters that were entered after the prompt. If you want this string interpreted as another type, you must provide the type conversion explicitly.
白話導讀

int、float、bool 與運算子,以及『變數持有的是資料的參考』這個關鍵觀念。

數值、布林與變數參考

int、float、bool 與運算子,以及『變數持有的是資料的參考』這個關鍵觀念。

STEP 1

深度探秘

int、float、bool 與運算子

Python 的原子型別

Python 把資料看成核心,是物件導向語言。最基本的『原子 (atomic)』型別有:

  • int:整數(如 23、-19)
  • float:浮點數(如 6.5)
  • bool:布林值,只有 TrueFalse

算術運算子的眉角

print(2 + 3 * 4)    # 14, 先乘後加
print((2 + 3) * 4)  # 20, 括號改變順序
print(2 ** 10)      # 1024, ** 是次方
print(6 / 3)        # 2.0, 兩整數相除得 float
print(7 // 3)       # 2, // 是整數除法 取整
print(7 % 3)        # 1, % 是取餘數 modulo

重點:兩個整數用 / 相除,結果是浮點數;想取整數部分要用 //,想取餘數要用 %

布林與比較

比較運算(==><= 等)的結果是布林值,可用 andornot 組成更複雜的判斷:

print((5 >= 1) and (5 <= 10))  # True
print(not (False or True))     # False
💡
關鍵

int、float、bool 是原子型別;// 取整、% 取餘、** 次方,比較與邏輯運算產生布林值。

STEP 2

生活妙喻

變數是貼在物品上的標籤

變數持有的是『參考

這是 Python 一個關鍵又容易誤會的觀念:變數持有的不是資料本身,而是指向資料物件的『參考 (reference)』

把變數想成一張便利貼標籤,資料物件則是倉庫裡的箱子:

  • the_sum = 0:貼一張寫著 the_sum 的標籤到『0』這個箱子上。
  • the_sum = the_sum + 1:算出『1』這個新箱子,把標籤撕下來改貼到『1』上。
  • the_sum = True:再把同一張標籤改貼到『True』這個箱子上。
flowchart LR
    L[標籤 the_sum] -->|現在指向| B1[資料物件 True]
    B0[資料物件 0]
    B2[資料物件 1]

動態型別

因為標籤可以隨時改貼到不同型別的箱子上,所以同一個變數可以先是整數、後變布林。這就是 Python 的動態 (dynamic) 特性。

💡
關鍵

變數像可重貼的標籤,指向資料物件;改值就是改貼標籤,型別也隨之改變。

STEP 3

實用超能力

命名與賦值的好習慣

識別字 (identifier) 規則

變數名稱(識別字)的規則:

  • 字母或底線 _ 開頭
  • 大小寫有別Sumsum 是兩個不同名字)
  • 長度不限

取有意義的名字

# 不好:別人看不懂
x = 3.14159 * r * r

# 好:一看就懂
area = 3.14159 * radius * radius

用能表達意義的名字,程式碼會好讀很多——這是寫給『未來的你』看的禮物。

賦值的運作順序

賦值時,Python 會先算右邊,再把結果物件的參考『指派』給左邊的名字:

the_sum = the_sum + 1  # 先算右邊 舊值+1, 再把標籤改貼過去
💡
關鍵

識別字以字母或底線開頭、大小寫有別;賦值先算右邊,再把名字指向結果。

🔆
生活妙喻:變數持有參考 ≈ 可重貼的便利貼標籤

變數是貼在資料箱子上的標籤,改值就是把標籤撕下來改貼到另一個箱子,因此同一變數能指向不同型別的資料。

🔆
生活妙喻:動態型別 ≈ 同一張標籤換貼不同箱子

標籤可貼整數箱也可貼布林箱,所以變數型別會隨它當下指向的資料而改變。

本節字彙

參考 (reference)
變數實際持有的東西:一個指向某個資料物件的『連結』,而不是資料本身。
🧠 變數是標籤,標籤上的箭頭指向資料箱子。
整數除法 //
回傳商的整數部分,捨去小數,例如 7 // 3 得到 2。
🧠 雙斜線『砍掉』小數,只留整數。
取餘數 %
回傳除法的餘數,例如 7 % 3 得到 1。
🧠 % 問的是『除不盡剩多少』。
動態型別 (dynamic typing)
變數的型別由它當下指向的資料決定,可隨賦值而改變。
🧠 標籤改貼哪種箱子,型別就跟著變。
在 Python 中,`print(7 // 3)` 與 `print(7 % 3)` 分別會印出什麼?
執行 `the_sum = 0` 後再執行 `the_sum = True`,關於 `the_sum` 的型別,正確的是?
為什麼說『變數持有的是參考,而不是資料本身』這個觀念很重要?

有序集合:list、string、tuple

三種有序序列共用索引、切片、串接等操作;list 可變、string 與 tuple 不可變。

STEP 1

深度探秘

三種有序序列

序列家族

Python 有三種有序集合 (ordered collection),又稱序列 (sequence)

型別 寫法 範例 可變
list 方括號 [] [1, 3, True, 6.5] 可變
string 引號 '' "" 'David' 不可變
tuple 圓括號 () (2, True, 4.96) 不可變

list 與 tuple 是異質的 (heterogeneous)——同一個集合裡可以放不同型別的資料。

序列共用的操作

因為都是序列,它們共用一組操作:

my_list = [1, 3, True, 6.5]
my_list[0]        # 索引: 取第 0 個
my_list[1:3]      # 切片: 取索引 1 到 2
len(my_list)      # 長度
[1, 2] + [3, 4]   # 串接 -> [1,2,3,4]
[0] * 6           # 重複 -> [0,0,0,0,0,0]
6.5 in my_list    # 成員測試 -> True

索引從 0 開始;切片 [1:3] 取到索引 3 之前(不含 3)。

💡
關鍵

list、string、tuple 都是有序序列,共用索引、切片、串接、重複、len、in 等操作。

STEP 2

生活妙喻

可變 vs. 不可變:白板與石碑

mutability(可變性)

list 與 string/tuple 最大的差別是可變性 (mutability)

  • list 是可變的 (mutable):像一塊白板,可以隨時擦掉某格重寫。
  • string 與 tuple 是不可變的 (immutable):像刻好的石碑,刻上去就不能改某個字。
my_list[0] = 1024   # OK, list 可改某格

my_name = 'David'
my_name[0] = 'X'    # 報錯 TypeError: 不支援 item assignment

為什麼要分這個?

想改某一格內容時,用 list;想要一份保證不會被偷改的資料時,用 tuple 或 string 更安全。這個差別在後面實作資料結構時會非常重要。

💡
關鍵

list 可變(像白板可改某格),string 與 tuple 不可變(像石碑不能改某字)。

STEP 3

實用超能力

list 方法、range 與小陷阱

常用的 list 方法

my_list = [1024, 3, True, 6.5]
my_list.append(False)   # 尾端加一個
my_list.insert(2, 4.5)  # 在索引 2 插入
my_list.pop()           # 移除並回傳最後一個
my_list.pop(1)          # 移除並回傳索引 1
my_list.sort()          # 就地排序
my_list.reverse()       # 就地反轉
my_list.index(4.5)      # 找第一個出現的索引

有些方法(如 pop)會回傳值並修改 list;有些(如 reverse)只修改、不回傳。

range 產生數列

list(range(10))       # [0,1,...,9]
list(range(5, 10))    # [5,6,7,8,9]
list(range(5, 10, 2)) # [5,7,9] 每次跳 2
list(range(10,1,-1))  # [10,9,...,2] 倒著走

重複運算子的陷阱

my_list = [1, 2, 3, 4]
A = [my_list] * 3   # A 裝的是 3 個指向同一個 list 的參考
my_list[2] = 45     # 改一個, 三份都跟著變!

因為 * 複製的是參考而非資料本身,這是初學者很容易踩到的坑。

💡
關鍵

list 有 append/insert/pop/sort 等方法;range 產生數列;重複運算子複製的是參考要小心。

🔆
生活妙喻:list 可變 vs. string/tuple 不可變 ≈ 白板 vs. 石碑

list 像白板可隨時擦改某一格;string 與 tuple 像刻好的石碑,內容固定不能改某個字。

🔆
生活妙喻:重複運算子複製參考 ≈ 三面鏡子照同一個人

[my_list]*3 像三面鏡子映出同一個人,本人一動三個影像都跟著動,因為它們指向同一份資料。

本節字彙

序列 (sequence)
有序的集合,元素有先後順序與索引;list、string、tuple 都是序列。
🧠 排好隊的資料,每個都有編號(索引)。
可變 / 不可變 (mutable / immutable)
可變物件(如 list)能就地修改內容;不可變物件(如 string、tuple)建立後不能改某個元素。
🧠 可變=白板,不可變=石碑。
切片 (slicing)
用 [i:j] 取出序列的一段,從索引 i 到 j 之前(不含 j)。
🧠 [1:3] 取 1、2,到 3 就停(不含 3)。
range
產生一段整數數列的物件,可指定起點、終點與間隔,終點不包含在內。
🧠 range(5,10) 是 5 到 9,10 永遠到不了。
下列哪一組型別『全部』都是不可變 (immutable) 的?
`my_name = 'David'` 後執行 `my_name[0] = 'X'` 會發生什麼?
`my_list = [10, 20, 30, 40, 50]`,那麼 `my_list[1:3]` 的結果是?

無序集合:set 與 dictionary

set 不允許重複、支援集合運算;dictionary 以 key-value 配對儲存、用鍵存取。

STEP 1

深度探秘

set:不重複的無序集合

set 是什麼

set(集合) 是一個無序不允許重複的集合,元素必須是不可變的物件。寫法是用大括號 {} 包起來、逗號分隔:

my_set = {3, 6, 'cat', 4.5, False}

注意:空集合要寫 set(),不能寫 {}(那會變成空字典)。

set 的運算(像數學集合)

my_set = {3, 6, 'cat'}
your_set = {99, 3, 100}
my_set | your_set   # 聯集 union
my_set & your_set   # 交集 intersection -> {3}
my_set - your_set   # 差集 difference
{3, 100} <= your_set  # 子集判斷 -> True
len(my_set)         # 元素個數
3 in my_set         # 成員測試

還有 addremovepopclear 等方法。因為不重複,set 很適合用來『去除重複』。

💡
關鍵

set 是無序、不重複的集合,支援聯集、交集、差集、子集等數學運算;空集合用 set()。

STEP 2

生活妙喻

dictionary:通訊錄查號簿

鍵-值配對組成的無序集合,用鍵來存取對應的值。">dictionary(字典)

dictionary(字典) 是無序的集合,由一組組鍵-值配對 (key-value pair) 組成,寫成 key:value

capitals = {'Iowa': 'DesMoines', 'Wisconsin': 'Madison'}
print(capitals['Iowa'])         # 用鍵查值 -> DesMoines
capitals['Utah'] = 'SaltLakeCity'  # 新增一對

像一本通訊錄

把字典想成通訊錄查號簿

  • 鍵 (key) 是『人名』(Iowa、Wisconsin)。
  • 值 (value) 是對應的『電話/首府』(DesMoines、Madison)。
  • 你用人名(鍵)去查電話(值),而不是用編號。
flowchart LR
    K1[鍵 Iowa] --> V1[值 DesMoines]
    K2[鍵 Wisconsin] --> V2[值 Madison]

字典沒有固定順序,鍵的擺放位置取決於一種叫雜湊 (hashing) 的技術(第 4 章會細講)。

💡
關鍵

dictionary 用鍵-值配對儲存,像通訊錄用人名查電話;無固定順序,靠雜湊決定位置。

STEP 3

實用超能力

字典的方法與安全取值

常用操作與方法

phone_ext = {'david': 1410, 'brad': 1137}
'brad' in phone_ext          # 鍵是否存在 -> True
del phone_ext['david']       # 刪除一對
list(phone_ext.keys())       # 所有鍵
list(phone_ext.values())     # 所有值
list(phone_ext.items())      # 所有 鍵,值 配對

get:安全地取值

直接用 my_dict[k] 取一個不存在的鍵報錯get 比較安全:

phone_ext.get('kent')             # 鍵不存在 -> 回傳 None, 不報錯
phone_ext.get('kent', 'NO ENTRY') # 鍵不存在 -> 回傳預設值 'NO ENTRY'

小技巧:當你不確定鍵在不在時,用 get 搭配預設值,可以避免程式因 KeyError 中斷。

💡
關鍵

用 in 判斷鍵、del 刪除、keys/values/items 取內容;get 可安全取值並設預設,避免報錯。

🔆
生活妙喻:dictionary 鍵值對 ≈ 通訊錄查號簿

用人名(鍵)查電話(值),而非用流水號;字典也是用鍵去查對應的值。

🔆
生活妙喻:set 不允許重複 ≈ 派對賓客名單

同一個人不管被邀請幾次,名單上只會出現一次,正如 set 自動去除重複元素。

本節字彙

set(集合)
無序、不允許重複的集合,支援聯集、交集、差集等運算;空集合寫成 set()。
🧠 像賓客名單:每個人只列一次。
dictionary(字典)
由鍵-值配對組成的無序集合,用鍵來存取對應的值。
🧠 通訊錄:用人名(鍵)查電話(值)。
鍵-值配對 (key-value pair)
字典的基本單位,一個鍵對應一個值,寫成 key:value。
🧠 鍵是『問題』,值是『答案』。
get 方法
安全取值的方法:鍵不存在時回傳 None 或指定的預設值,而不會報錯。
🧠 查不到時不發脾氣,回傳 None 或你給的備案。
把清單 `[3, 3, 6, 6, 6, 'cat']` 轉成 set 後,最可能的結果特性是?
`capitals = {'Iowa': 'DesMoines'}`,要取得 Iowa 的首府,應該怎麼寫?
`{3, 6} & {6, 9}` 與 `{3, 6} | {6, 9}` 的結果分別是?
04

Python 控制流程與程式組織

input 讀進來都是字串、print 的彈性輸出,以及用格式運算子排版輸出。

先讀原文段落,旁邊就是白話

這是一本英文書。左邊放原文、右邊放白話導讀——你既讀得懂,也順手碰了原文。

原文 · Python 控制流程與程式組織 Any characters that follow the # on a line are ignored. 1: square_root Function def square_root(n): root = n / 2 #initial guess will be 1/2 of n for k in range(20): root = (1 / 2) * (root + (n / root)) return root >>>square_root(9) 3. 0 >>>square_root(4563) 67. 549981495186216 >>> Self Check Here is a self check that really covers everything so far.
白話導讀

input 讀進來都是字串、print 的彈性輸出,以及用格式運算子排版輸出。

輸入輸出與字串格式化

input 讀進來都是字串、print 的彈性輸出,以及用格式運算子排版輸出。

STEP 1

深度探秘

input 讀進來永遠是字串

input 函式

程式常需要跟使用者互動。Python 用 input 函式請使用者輸入資料,它接受一個字串參數作為提示 (prompt)

user_name = input('請輸入你的名字:')

使用者打的東西會存進 user_name

關鍵陷阱:回傳的永遠是 str

input 回傳的永遠是字串,即使使用者打的是數字!

想當數字算術,必須自己明確轉型

user_radius = input('請輸入半徑:')
radius = float(user_radius)   # 字串轉浮點數
diameter = 2 * radius          # 現在才能算術

如果忘了轉型直接 user_radius * 2,會變成把字串重複兩次而不是乘以二,這是很常見的 bug。

💡
關鍵

input 回傳的永遠是字串,要做數字運算前必須用 int() 或 float() 明確轉型。

STEP 2

生活妙喻

print 像可調整的印章

print 的彈性

print 可印零個或多個值,預設用一個空白分隔、結尾換行。這兩個行為都能調:

print('Hello', 'World')                # Hello World
print('Hello', 'World', sep='***')     # Hello***World
print('Hello', 'World', end='***')     # Hello World***(不換行)

像一台可換設定的印章機

print 想成一台印章機

  • sep(分隔):決定多個字之間蓋什麼分隔符(預設是空格)。
  • end(結尾):決定每次蓋完印章後接什麼(預設是換行)。

換掉這兩個設定,就能控制輸出長相,而不必改動要印的內容本身。

💡
關鍵

print 可印多個值,用 sep 調整分隔符、end 調整結尾(預設換行),靈活控制輸出外觀。

STEP 3

實用超能力

格式字串:填空模板

格式字串 (formatted string)

想更精細控制輸出排版時,用格式字串:一個帶佔位符的模板,再把變數填進去。%格式運算子

name = 'Ann'
age = 18
print('%s is %d years old.' % (name, age))
# Ann is 18 years old.
  • 左邊是模板,含轉換規格%s(字串)、%d(整數)、%f(浮點數)。
  • 右邊是要填入的值(依序對應)。

加上格式修飾子

% 與轉換字元之間可加修飾子,控制欄寬與小數位:

item = 'banana'; price = 24
print('The %+10s costs %5.2f cents' % (item, price))
# %5.2f: 欄寬 5、小數 2 位 -> 24.00
規格 意思
%d 整數
%f 浮點數
%s 字串
%5.2f 欄寬 5、小數 2 位

右邊值的個數要與模板中 % 的個數一致,否則會出錯。

💡
關鍵

格式字串用 % 把變數填進模板,%s/%d/%f 指定型別,並可加修飾子控制欄寬與小數位。

🔆
生活妙喻:print 的 sep 與 end ≈ 可換設定的印章機

sep 決定字與字之間蓋什麼分隔、end 決定每次印完接什麼,換設定就能改變輸出外觀而不動內容。

🔆
生活妙喻:格式字串 ≈ 填空題的模板

格式字串像一張留好空格的模板,%s、%d 是空格的型別標示,右邊的值依序填進去。

本節字彙

input
請使用者輸入資料的函式,接受一個提示字串,回傳值永遠是字串 (str)。
🧠 不管打什麼進去,拿回來的都是字串。
型別轉換 (type conversion)
把資料從一種型別轉成另一種,如 int()、float()、str()。
🧠 輸入要算數,先 float() 或 int() 一下。
格式運算子 %
把右邊的值依照左邊模板中的轉換規格填入字串的運算子。
🧠 % 左邊是模板,右邊是要填的值。
轉換規格 (%s/%d/%f)
格式字串中標示要填入值之型別的記號:%s 字串、%d 整數、%f 浮點數。
🧠 s=string、d=digit(整數)、f=float。
使用者在 `n = input('請輸入數字:')` 輸入了 5,接著執行 `print(n * 2)`,會印出什麼?
想把使用者輸入的半徑拿來做算術,正確的做法是?
`print('A', 'B', sep='-', end='!')` 會輸出什麼(用文字描述)?

迭代與選擇

while 與 for 兩種迴圈、if/else 選擇,以及一行搞定的串列推導式。

STEP 1

深度探秘

兩種迴圈:while 與 for

迭代 (iteration)

演算法需要『重複』的能力。Python 有兩種迴圈:

while:條件成立就一直做

counter = 1
while counter <= 5:
    print('Hello, world')
    counter = counter + 1

每次重複前都會先檢查條件,True 才執行本體。條件可以是複合的:

while counter <= 10 and not done:
    ...

for:走訪序列或 range

for item in [1, 3, 6, 2, 5]:
    print(item)

for item in range(5):     # 定次迭代 0~4
    print(item ** 2)

for 可走訪任何序列(list、tuple、string),也常搭配 range定次迭代 (definite iteration)

注意 Python 用縮排而非大括號來標示迴圈本體,縮排是語法的一部分。

💡
關鍵

while 依條件重複(每次先檢查),for 走訪序列或用 range 做定次迭代;縮排標示本體。

STEP 2

生活妙喻

選擇就是路口的紅綠燈

選擇 (selection)

選擇讓程式問問題、再依答案做不同的事。把它想成路口的紅綠燈與分岔路

if/else:雙向分岔

if n < 0:
    print('抱歉,值是負數')
else:
    print(math.sqrt(n))

像路口問『紅燈嗎?』——是就停,否就走,兩條路擇一

巢狀選擇:一連串的分岔

if score >= 90:
    print('A')
else:
    if score >= 80:
        print('B')
    else:
        if score >= 70:
            print('C')
        else:
            print('D 或 F')

單向 if:只有『要不要做』

if n < 0:
    n = abs(n)   # 是負數才取絕對值
print(math.sqrt(n))  # 不管怎樣都會執行這行

單向 if 像『前方施工才繞道,否則直接直行』。

💡
關鍵

if/else 是雙向分岔、可巢狀串接多個條件;單向 if 只決定『要不要做某事』,之後照常往下。

STEP 3

實用超能力

一行搞定的串列推導式

串列推導式 (list comprehension)

當你想『用迭代+選擇建立一個新 list』,串列推導式能把好幾行濃縮成一行。

從迴圈版到推導式版

# 迴圈版:前 10 個完全平方數
sq_list = []
for x in range(1, 11):
    sq_list.append(x * x)

# 推導式版:一行搞定
sq_list = [x * x for x in range(1, 11)]
# [1, 4, 9, ..., 100]

加上篩選條件

sq_list = [x * x for x in range(1, 11) if x % 2 != 0]
# 只留奇數的平方 -> [1, 9, 25, 49, 81]

結尾加 if 條件 就能只把符合的項目放進新 list。

[ch.upper() for ch in 'comprehension' if ch not in 'aeiou']
# ['C','M','P','R','H','N','S','N'] 去掉母音並轉大寫

任何支援迭代的序列都能用在推導式裡,是非常實用、Pythonic 的寫法。

💡
關鍵

串列推導式把迭代與選擇濃縮成一行來建立新 list,結尾加 if 可篩選項目。

🔆
生活妙喻:if/else 選擇 ≈ 路口的紅綠燈與分岔路

程式在路口問一個問題,依答案走不同的路;if/else 是雙向擇一,巢狀則是一連串分岔。

🔆
生活妙喻:for 定次迭代 ≈ 點名簿逐一唱名

for 走訪序列就像老師拿點名簿一個個唱名,每個元素都被輪到處理一次。

本節字彙

while 迴圈
只要條件為 True 就重複執行本體的迴圈,每次重複前先檢查條件。
🧠 『當…還成立時』就一直做。
for 迴圈
逐一走訪序列或 range 中每個元素的迴圈,適合定次迭代。
🧠 『對每一個元素』做一次。
定次迭代 (definite iteration)
事先知道要重複幾次的迭代,常用 for 搭配 range 實現。
🧠 次數先講好,跑 range 就對了。
串列推導式 (list comprehension)
用一行語法結合迭代(與可選的篩選)來建立新 list 的寫法。
🧠 [運算 for 元素 in 序列 if 條件]:一行造出新清單。
下列情境最適合用 `for` 搭配 `range` 的是?
關於單向 `if`(沒有 else),下列敘述何者正確?
`[x * x for x in range(1, 6)]` 的結果是?

例外處理

分清語法錯誤與邏輯錯誤,用 try/except 攔截例外,用 raise 主動拋出例外。

STEP 1

深度探秘

兩種錯誤:語法 vs. 邏輯

寫程式常見的兩類錯誤

語法錯誤 (syntax error)

程式碼結構寫錯,違反語言規則,連跑都跑不起來。例如 for 後面忘了冒號:

>>> for i in range(10)
SyntaxError: invalid syntax

剛學語言時最常犯這種錯。

邏輯錯誤 (logic error)

程式跑得起來,卻給出錯的結果——可能是演算法本身有問題,或翻譯成程式時出錯。

有些邏輯錯誤更嚴重,會在執行時引發致命狀況,例如除以零、或存取超出範圍的索引。這類執行期錯誤就稱為例外 (exception)

flowchart TD
    E[寫程式的錯誤] --> S[語法錯誤 結構寫錯 跑不起來]
    E --> L[邏輯錯誤 跑得起來但答案錯]
    L --> X[執行期例外 如除以零 索引越界]
💡
關鍵

語法錯誤是結構寫錯跑不起來;邏輯錯誤是跑得起來卻答案錯,嚴重時引發執行期例外。

STEP 2

生活妙喻

try/except 是安全網

例外被『raise(拋出)』

當例外發生,我們說它被**『raise(拋出)』了。預設情況下,例外會讓程式中斷**。

例如對負數開根號:

>>> print(math.sqrt(-23))
ValueError: math domain error

try/except:接住失誤的安全網

你可以用 try 區塊『嘗試』做某事,再用 except 區塊**『接住』萬一發生的例外,像走鋼索下方的安全網**:

try:
    print(math.sqrt(a_number))
except:
    print('開根號的值不合法')
    print('改用絕對值')
    print(math.sqrt(abs(a_number)))

如果 sqrt 拋出例外,程式不會中斷,而是掉進 except 區塊處理善後,再繼續往下跑。

安全網的價值:即使踩空了,表演(程式)也能優雅地繼續,而不是當場墜落(崩潰)。

💡
關鍵

例外發生時會被 raise,預設讓程式中斷;用 try/except 可像安全網般接住例外並優雅善後。

STEP 3

實用超能力

主動 raise 自己的例外

你也可以主動拋出例外

除了被動接住,程式設計師也能用 raise 主動拋出例外——當你偵測到一個不該發生的狀況時:

if a_number < 0:
    raise RuntimeError('不可以用負數')
else:
    print(math.sqrt(a_number))

這時程式一樣會因為例外而終止,但這個終止是你刻意設計的,而且訊息清楚說明了原因。

為什麼這是超能力

  • 提早攔截:在錯誤資料造成更大災難前就喊停。
  • 訊息明確:自訂的例外訊息讓除錯快很多。
  • 除了 RuntimeError,Python 還有 ValueErrorTypeError 等許多內建例外型別可用,也能自訂。

主動 raise 等於在程式裡裝『警報器』:一偵測到不合理的狀況,立刻響鈴並說清楚哪裡出問題。

💡
關鍵

用 raise 可主動拋出例外,在偵測到不合理狀況時提早喊停並給出清楚的錯誤訊息。

🔆
生活妙喻:try/except ≈ 走鋼索下方的安全網

try 區塊是走鋼索,except 是下方的安全網;萬一失誤(拋出例外),網子接住你,表演還能繼續而非墜落崩潰。

🔆
生活妙喻:主動 raise 例外 ≈ 裝在程式裡的警報器

偵測到不合理的狀況就主動拉警報(raise),立刻喊停並說明原因,避免錯誤資料釀成更大災難。

本節字彙

語法錯誤 (syntax error)
程式碼結構違反語言規則,導致無法執行,例如忘了冒號或括號不對。
🧠 句子文法寫錯,根本讀不通。
邏輯錯誤 (logic error)
程式能執行但結果錯誤,源自演算法或翻譯成程式時的錯誤。
🧠 跑得動,但答案不對。
例外 (exception)
執行期發生的錯誤(如除以零、索引越界),預設會中斷程式。
🧠 執行到一半突然『出狀況』。
try / except
try 嘗試執行可能出錯的程式碼,except 接住並處理發生的例外。
🧠 try 走鋼索,except 是安全網。
raise
主動拋出一個例外的敘述,常用於偵測到不合理狀況時提早喊停。
🧠 自己拉警報,主動喊停。
程式可以順利執行,但算出來的平均分數明顯是錯的。這屬於哪一類錯誤?
使用 `try/except` 包住 `math.sqrt(a_number)` 的主要好處是?
當一個例外發生卻沒有被任何 try/except 接住,預設會怎樣?

函式與類別

用函式隱藏計算細節,用 class 定義新型別來實作 ADT,認識建構子與 self。

STEP 1

深度探秘

用函式把細節裝進盒子

定義class="term" data-definition="有名稱、參數、本體並可回傳值的程式單位,用來封裝一段可重複使用的運算。">函式

函式讓我們把一段運算的細節藏起來(還記得程序抽象化嗎?)。一個函式定義需要:

  • 名稱
  • 一組參數 (parameters)
  • 本體 (body)
  • 可選擇地回傳 (return) 一個值
def square(n):
    return n ** 2

square(3)          # 9
square(square(3))  # 81 回傳值可再傳入

n形式參數 (formal parameter);呼叫時傳入的 3實際參數 (actual parameter)

用函式實作演算法

def square_root(n):
    root = n / 2          # 初始猜測為 n 的一半
    for k in range(20):   # 牛頓法 反覆逼近 20 次
        root = (1 / 2) * (root + (n / root))
    return root

牛頓法的更新公式為:

$$new_guess = \frac{1}{2}\left(old_guess + \frac{n}{old_guess}\right)$$

使用者只要呼叫 square_root(9) 得到 3.0,完全不需要知道牛頓法的細節——這就是抽象化的威力。# 之後的文字是註解,會被忽略。

💡
關鍵

函式有名稱、參數、本體與可選回傳值,能把運算細節藏進盒子,呼叫者不必懂內部實作。

STEP 2

生活妙喻

類別是『餅乾模具』

用 class 定義新型別

物件導向最強的能力,是讓你自訂新的類別 (class) 來模擬要解的資料。回想前面:ADT 描述資料的狀態 (state)行為 (method),而用 class 實作 ADT,就把抽象變成可用的東西。

餅乾模具與餅乾

class 想成餅乾模具,把 object(物件) 想成用模具壓出來的一塊塊餅乾

  • 模具(class)定義了餅乾長什麼樣、能做什麼
  • 每壓一次就產生一個實例 (instance)——一塊獨立的餅乾(object)。
class Fraction:
    def __init__(self, top, bottom):
        self.num = top      # 狀態 分子
        self.den = bottom   # 狀態 分母
flowchart LR
    C[class Fraction 模具] -->|壓一次| O1[物件 三分之五]
    C -->|再壓一次| O2[物件 二分之一]

同一個模具能壓出無數塊餅乾,每塊餅乾有自己的狀態(各自的分子分母)。

💡
關鍵

class 像餅乾模具,定義資料的狀態與行為;每個 object 是壓出來的一塊獨立餅乾(實例)。

STEP 3

實用超能力

建構子 __init__ 與 self

建構子 init

所有類別都該提供的第一個方法是建構子 (constructor),它定義物件如何被建立。在 Python 中建構子固定叫 __init__(init 前後各兩個底線):

class Fraction:
    def __init__(self, top, bottom):
        self.num = top
        self.den = bottom

my_fraction = Fraction(3, 5)  # 呼叫類別名 即觸發建構子

注意:我們用類別名來建立物件,而不直接呼叫 init

self 是什麼

  • self 是特殊參數,永遠是第一個形式參數,代表物件自己
  • 呼叫時不需要手動給 self 傳值。
  • self.num = top 表示『在這個物件身上,建立一個叫 num 的內部狀態』。

為什麼物件要會『自我介紹』

直接 print(my_fraction) 會印出像 <__main__.Fraction object at 0x...> 這種看不懂的東西,因為物件還不知道怎麼把自己變成漂亮的字串。要讓它好好顯示(如印成 3/5),就得告訴類別怎麼把自己轉成字串——這正是用方法擴充物件行為的起點。

💡
關鍵

建構子 __init__ 定義物件如何被建立並初始化狀態;self 永遠是第一個參數,代表物件自己。

🔆
生活妙喻:class 與 object ≈ 餅乾模具與餅乾

class 是模具,定義餅乾的樣子與功能;每壓一次就產生一塊獨立的餅乾(object),各有自己的狀態。

🔆
生活妙喻:函式隱藏細節 ≈ 自動販賣機

你投錢按鈕(給參數)就拿到飲料(回傳值),不必知道機器內部怎麼運作,正如函式把實作藏在裡面。

本節字彙

函式 (function)
有名稱、參數、本體並可回傳值的程式單位,用來封裝一段可重複使用的運算。
🧠 投入參數,吐出結果的小盒子。
類別 (class)
描述資料狀態與行為的藍圖,用來實作抽象資料型別 (ADT)。
🧠 餅乾模具:定義餅乾長怎樣、能做什麼。
物件 / 實例 (object / instance)
依類別建立出來的具體資料,每個物件有自己的狀態。
🧠 用模具壓出來的一塊塊餅乾。
建構子 __init__
建立物件時自動呼叫的方法,負責初始化物件的狀態。
🧠 物件出生時的『初始化儀式』。
self
方法中代表物件自己的特殊第一參數,呼叫時不需手動傳值。
🧠 self = 『我這個物件自己』。
呼叫 `square_root(9)` 得到 3.0,但你完全不需要知道它內部用了牛頓法。這再次體現了哪個觀念?
用『餅乾模具與餅乾』比喻,`class Fraction` 與 `Fraction(3, 5)` 分別對應?
關於建構子 `__init__`,下列何者正確?