聯繫我們
加入好友
PY101

為你自己學 Python

給新手的 Python 線上程式課程

這是給想要學習 Python 的新手所寫的線上課程。 文字版教材:https://pythonbook.cc/ 本課程以 Python 3 做為主要教學語言,第一單位(PY101)內容涵蓋 Python 環境安裝、程式語言基礎語法,包括各種常用資料型態介紹、邏輯及流程控制、函數、物件導向程式設計等,並透過網站爬蟲程式抓取並分析資料。

現在報名只要 NT$3,800
  • 終身存取權
  • 可行動裝置使用
  • 課程時長:25.4 小時
  • 結業證書

講師介紹

使用者大頭貼

高見龍 Eddie

五倍學院負責人,在國內外各大型技術研討會擔任講者,參與過日本 RubyKaigi、日本 Ruby World Conference、臺灣微軟 Azure Developer Day 、RubyConf Taiwan、JSDC、WebConf Taiwan 等。有二十年程式開發經驗和十多年的教學經驗,在臺灣推廣 Ruby 及 Git 多年,在各大專院校與企業開課,深受學員喜愛。

非資訊本科系出身,但喜歡寫程式,而且希望可以寫一輩子程式的電腦阿宅。

著有「為你自己學 Git」與「為你自己學 Ruby on Rails」暢銷技術書。

課程特色

課程章節

第 1 章:寫在最前面

00 : 13 : 33

101 - 寫在最前面

Python 入門內容,教材已放上「為你自己學 Python」網站,採用 CC 授權免費取用。這本書的起源是因為我家小孩學校要教 Python,所以寫了一本讓新手也能看懂的書。Python 目前在 TIOBE 排行榜位居第一,可用於自動化程式、網頁爬蟲、網站開發及機器學習等領域。學習上我建議不要只是照著影片打字,而是先暫停影片自己嘗試撰寫,並透過「小黃鴨除錯法」講解給自己聽。最重要的是建立 SSOT(單一真相來源),以官方文件為準,使用 AI 工具時要小心求證。

第 2 章:環境安裝

01 : 50 : 17

201 - 安裝 Python

09 : 07

安裝 Python 程式語言。Mac 系統通常已內建 Python,但版本較舊,建議另外安裝新版。Python 2 和 3 不相容,現在普遍使用 Python 3。安裝過程很簡單,下載後一路按下一步即可完成。Mac 用戶可透過終端機輸入 python3 來執行,Windows 用戶則可用 PowerShell 輸入 python。若要離開 Python 環境,可輸入 exit() 或按 Ctrl+D。整體來說,Python 的安裝比其他程式語言簡單許多。

202 - REPL

REPL 是 Read、Evaluate、Print、Loop 四個字的縮寫。在這個環境中,系統會讀取你輸入的內容,評估執行後印出結果,然後等待下一個指令。例如在終端機輸入 python3 進入 REPL 環境後,輸入 1 就會印出 1,輸入 1 加 2 就會計算並印出 3。REPL 環境的提示符號是三個箭頭,輸入指令時不需要跟著打這三個箭頭。這個環境很適合用來執行簡單的程式或做測試,但不適合撰寫較長的程式碼。

203 - 安裝 pyenv

17 : 08

pyenv 這個 Python 版本管理工具。Python 有很多版本和分支,像是 Jython、IronPython、PyPy 等,光是 3 系列就有 3.10、3.11、3.12 等多個版本。pyenv 本身不是 Python,而是一個工具箱,可以在同一台電腦安裝並管理多個 Python 版本。Mac 用戶需先安裝 Homebrew,再用 brew install pyenv 安裝;Windows 用戶則透過 PowerShell 安裝。安裝後可用 pyenv install 安裝指定版本,用 pyenv shell 或 pyenv global 切換版本。設定 global 後,每次開啟終端機都會使用指定版本,且可直接打 python 而不用打 python3。

204 - 安裝 VSCode

01 : 18

只要有文字編輯器就能開始寫 Python 程式,不需要很厲害的工具。市面上有 PyCharm 這類功能完整的開發工具,雖然有免費的社群版本,但它是商業公司開發的,啟動速度稍慢。在這個課程中,我會使用 VS Code 這個文字編輯器,它簡單好用,在 Mac 和 Windows 都有對應版本,下載安裝後就能開始寫程式了。

205 - 第一個程式

13 : 17

示範如何用 Python 印出第一行程式。首先介紹用 python -c 指令直接執行一行程式碼,以及進入 REPL 環境互動執行,但這些方式不實用。接著說明正式開發流程:用 VS Code 開啟資料夾,建立 .py 檔案撰寫程式碼。推薦安裝 Python 和 Black Formatter 這兩個擴充套件,前者提供語法提示,後者自動排版。VS Code 內建終端機很方便,不用額外切換視窗就能執行腳本。雖然也能用 Google Colab 或 Jupyter Notebook,但建議在本機開發,把技能學進腦袋,不要被特定工具綁架。

206 - 註解

03 : 16

註解是用井字號開頭的說明文字,目的是解釋程式碼的用途,例如說明 9.8 代表重力加速度。適當加註解能幫助同事或未來的自己理解程式碼的意圖。註解不會被程式執行,所以也常用來暫時停用某段程式碼,方便測試不同情況。在 VS Code 中,可用快捷鍵 Ctrl 或 Command 加斜線快速切換註解,還能一次選取多行批次處理,非常實用。學會這些小技巧能讓開發過程更順暢,也展現你對工具的熟練度。

207 - Python 附檔名

03 : 00

檔案副檔名其實只是用來標記的,告訴作業系統這是什麼類型的檔案。Python 程式不一定要存成 .py,改成 .js、.php 甚至 .jpg 都能正常執行,因為本質上它就是個文字檔,Python 直譯器只在乎檔案內容,不在乎副檔名叫什麼。副檔名的主要用途是讓作業系統知道雙擊時該用什麼程式開啟,像 .doc 會開 Word、.xls 會開 Excel。不過實務上還是建議用 .py,因為 VS Code 等編輯器會根據副檔名提供正確的語法高亮顯示,改成其他副檔名反而會造成困擾。

208 - Python 之禪

01 : 55

在 Python 的 REPL 環境中輸入 import this,會顯示一段由核心開發者 Tim Peters 所寫的文字,稱為「Python 之禪」(Zen of Python)。這段文字列出了撰寫 Python 程式碼的原則,包括:優美優於醜陋、可讀性很重要、簡單優於複雜等。這些原則是寫 Python 時應該放在心裡的指引,遵循這些方向就能寫出更優美、簡潔、明瞭的程式碼。雖然初學階段可能還感受不到這些原則的好處,但寫個半年、一年之後,就會慢慢體會為什麼大家這麼喜歡 Python 這個程式語言。

209 - 安裝套件

08 : 31

Python 本身功能有限,大多需要依賴第三方套件。現在透過 PyPI 網站可以找到各種套件,類似 JavaScript 的 NPM 或 Ruby 的 RubyGems。安裝套件只需執行 pip install 加上套件名稱即可,pip 會自動處理相依套件的下載與安裝,比早期手動下載解壓縮方便許多。用 pip list 可查看已安裝的套件。不過 pip 有個問題:uninstall 時只會移除指定套件,不會連帶移除相依套件,導致殘留檔案。這雖然造成空間浪費,但更大的問題與接下來要談的虛擬環境有關。

210 - 虛擬環境 venv

17 : 28

pip 安裝套件時,同一環境只能存在一個版本,安裝新版會自動移除舊版,造成不同專案間的版本衝突。venv 是 Python 3.3 後內建的模組,可為每個專案建立獨立環境,透過 python -m venv 環境名稱 建立,再用 source 啟動。啟動後安裝的套件只存在該環境中,不影響其他專案。Mac 與 Windows 的啟動指令略有不同。另外說明 pyenv 管理 Python 版本,venv 管理套件版本,兩者層級不同。最後介紹 pip freeze 可輸出套件清單至 requirements.txt,方便部署時用 pip install -r 批次安裝。

211 - 套件管理工具 Poetry part 1

15 : 21

venv 的缺點是移除套件時,相依的延伸套件不會一併移除,雖然只是浪費空間,但用起來不太舒服。Poetry 的角色類似前端的 NPM,功能更完整。安裝時建議用 pipx 來安裝,讓 Poetry 成為全域工具,不會跟虛擬環境混在一起。使用 poetry new 或 poetry init 可以建立專案,會產生 pyproject.toml 設定檔。透過 poetry add 安裝套件、poetry remove 移除套件時,相依套件會一併處理。Poetry 還會產生 lock 檔確保版本一致,也支援用 --group 參數將開發用套件分組管理。

212 - 套件管理工具 Poetry part 2

18 : 00

Poetry 預設會把虛擬環境放在系統目錄,不像 venv 放在專案資料夾內,想查看位置可用 poetry env info 指令。我習慣修改設定讓虛擬環境建在專案內,方便管理和刪除,只要執行 poetry config virtualenvs.in-project true 即可。另外說明語意化版本的概念:主版號代表大改版、次版號代表新功能、修訂版號代表小修正。pyproject.toml 中的版本符號也很重要,波浪符號只升級修訂版,插入符號會升級次版號,等於等於則鎖定版本。建議不要太保守,以免錯過安全性更新。

第 3 章:變數

00 : 48 : 55

301 - 變數與常數

16 : 36

介紹 Python 變數的基本概念與使用方式。變數就像標籤或名牌,用來標記電腦記憶體中的資料,方便後續存取。在 Python 中宣告變數非常簡單,不需要像其他程式語言那樣先宣告型別,直接寫 a = 1450 即可。示範如何使用 print() 印出變數值,並說明變數名稱與字串的差異。Python 支援多重指定,可一次宣告多個變數如 x, y, z = 1, 2, 3,若有不需要的值可用底線 _ 代替。變數的值可隨時更改,但存取不存在的變數會出現 not defined 錯誤。最後提到 Python 沒有常數設計,慣例上用全大寫命名表示不應修改的值。

302 - 變數命名規則

07 : 13

介紹 Python 變數命名規則。變數名稱可以使用文字、底線開頭,支援中文、日文等多種語言,但實務上建議用英文。數字可以出現在變數名稱中,但不能放在開頭,否則會產生 syntax error。大小寫視為不同變數,例如 a 和 A 是兩個不同的變數。Python 有 35 個保留字如 if、else 等,這些是語法專用,不能拿來當變數名稱。可以用 help() 函數查詢關鍵字或語法說明。另外還有「軟關鍵字」的概念,像底線、case、match、type 這四個,平常可以當變數使用,但在特定語法情境下會變成關鍵字。

303 - 命名慣例

04 : 53

介紹程式設計中常見的變數命名慣例。首先是駝峰式命名法(Camel Case),開頭小寫,單字間用大寫字母區隔,看起來像駱駝的駝峰。還有 Pascal 命名法,連開頭都大寫。接著是蛇式命名法(Snake Case),全部小寫並用底線分隔,這是 Python 和 Ruby 常用的方式。最後是烤肉串式命名法(Kebab Case),用橫槓分隔,但在 Python 等多數程式語言中是不合法的語法。雖然 Python 用駝峰式也能執行,但入境隨俗,建議還是採用蛇式命名法,這是 Python 社群的慣例。

304 - 程式碼可讀性

03 : 07

介紹程式碼可讀性的重要性,特別是變數命名。程式碼寫一次但要讀很多次,不管是自己日後回顧或同事閱讀,好的命名能讓人一眼看懂意義。例如 a = 18 讓人摸不著頭緒,但 age = 18 就能立刻理解是年齡。電腦不在乎變數名稱,但工程師需要。電腦科學有兩大難題:cache 和 naming things,甚至有人專門出書探討命名。cache 的難處在於不知道何時該清除暫存更新內容,就像人生不知何時該放手。最後提到 Python 建議使用蛇式命名法,以底線分隔單字。

305 - 《練習》變數交換

04 : 04

介紹 Python 變數交換的兩種方法。首先用碗和球的比喻說明,若要交換兩個變數的值,一次只能操作一個,因此需要第三個暫存變數。示範先將 Goku 存入 temp,再把 Ginyu 指定給 Goku,最後將 temp 指定給 Ginyu,完成三角輪調。這是一般程式語言的標準做法。接著介紹 Python 特有的簡潔寫法,利用多重指定的特性,一行程式碼就能完成交換,不需要額外的暫存變數。這種寫法其實是利用 Tuple 的特性實現,後續章節會詳細說明。

306 - 刪除變數

01 : 54

介紹 Python 的 del 語法,用於刪除變數。實際上在 Python 程式設計中很少需要手動刪除變數,因為程式執行完畢後,變數會自動歸還給系統。但如果想手動刪除,可以使用 del 關鍵字。示範建立一個變數 sister 並印出內容,接著使用 del 刪除該變數後,再次印出就會出現 not defined 錯誤,表示變數已被移除,或者說標籤已被撕掉。雖然 Python 提供這個語法,但實務上不太需要主動刪除變數,Python 的垃圾回收機制會自動處理這些事情。

307 - 使用者輸入

03 : 34

介紹 Python 的 input 函數,讓程式能與使用者互動。首先用 print 印出問題詢問使用者年齡,接著透過 input 這個內建函數取得使用者輸入的內容,並將結果存入變數中。當程式執行到 input 時會暫停等待輸入,使用者按下 Enter 後,輸入的資料就會存進變數,再透過 print 把結果印出來。這個技巧可以應用在許多互動程式上,例如猜拳、剪刀石頭布或猜數字遊戲。對於初學者來說,能讓程式與電腦產生互動是相當有趣的體驗。

308 - 宣告型別?

07 : 34

介紹 Python 的型別註記(Type Annotation)功能。Python 原本宣告變數不需指定型別,變數可以隨意改變內容,這種設計比較自由。但從 Python 3.5 開始提供型別註記,寫法是在變數名稱後加冒號和型別,例如 age: int = 18。這樣做的好處是讓 VS Code 或 PyCharm 等開發工具能提供更精確的方法提示。不過要注意,Python 的型別註記只是「僅供參考」,並沒有強制力,就算宣告是整數卻給文字,程式也不會報錯。這個功能主要是寫給隊友或開發工具看的,如果需要嚴格檢查,可以使用 mypy 等工具。至於該不該用,就看團隊習慣。

第 4 章:數字與文字

02 : 42 : 35

401 - 整數與浮點數

03 : 13

Python 把數字分成兩種型別:整數(integer)和浮點數(float)。對人類來說,123 和 123.0 意思相同,但電腦分得很清楚,只要帶小數點就是浮點數。使用內建函數 type() 可以查看資料型別,例如 type(123) 會顯示 int,而 type(123.0) 則顯示 float。這兩種型別在電腦世界裡是完全不同的東西,這點跟我們日常生活的認知不太一樣。下個主題會介紹文字,也就是字串。

402 - 數字四則運算

07 : 19

Python 的四則運算使用 +-*/ 符號,其中除法會自動產生浮點數結果,即使運算元都是整數。若需要整數除法,可用雙斜線 //,餘數會被捨棄。運算式中只要出現浮點數,結果就會變成浮點數。Python 遵循先乘除後加減的數學規則,可用小括號改變優先順序。與 JavaScript 不同,Python 不允許數字與字串直接相加,這種嚴格的型別檢查其實是好事。另外,** 代表次方運算,% 則用來取餘數,常用於判斷整除關係。

403 - 四捨五入

09 : 29

Python 內建的 round() 函數可做四捨五入,第二個參數可指定小數位數。不過 Python 3 採用的是「銀行家捨入法」,遵循 IEEE 754 標準。當數字剛好落在中間值(如 0.5)時,會捨入到最接近的偶數,而非傳統的無條件進位。例如 round(0.5) 結果是 0,round(1.5) 則是 2。這樣設計是為了解決傳統四捨五入的偏差問題,因為 1-4 捨去、5-9 進位的分配並不公平。另外要注意,浮點數在電腦中無法精確表示,像 2.675 取到小數第二位會得到 2.67 而非 2.68,因為實際儲存的值略小於 2.675。

404 - 其它數學運算

06 : 28

Python 的 math 模組提供 ceil 和 floor 函數,分別用於無條件進位和無條件捨去。ceil 是天花板,代表往上取整;floor 是地板,代表往下取整。Python 官方認為這些函數使用頻率較低,因此放在 math 模組中,需要時再匯入。整數的最大位數預設為 4300 位,超過會報錯,但可調整上限。整數和浮點數之間可用 int 和 float 函數互相轉換,int 轉換時會無條件捨去小數部分。這兩個函數也能將字串轉換成數字,是常用的型別轉換工具。

405 - a = a + 1

05 : 12

在程式設計中,單一等號不是數學上的「等於」,而是「指定」(assign)的意思。例如 a = 1 表示把 1 指定給變數 a。所以 A = A + 1 這個看似矛盾的式子,其實是把 A 目前的值加 1 後,再指定回 A,達成遞增效果。這種寫法可以簡化成 A += 1,把加號移到等號前面。同樣道理,-=*=/= 分別代表減、乘、除後再指定回來。Python 沒有其他語言的 ++-- 寫法,我覺得這樣反而更清楚。記住:一個等號是指定,不是比較。

406 - 科學記號表示法

08 : 47

科學記號表示法用來簡化極大或極小的數字,例如 6.02 乘以 10 的 23 次方,省略部分細節只保留重要位數。電腦內部只認得 0 和 1,採用二進位運算。十進位轉二進位時,整數部分通常沒問題,但小數部分常無法整除,會產生無限位數。例如 7.625 能完美轉換,但 7.626 就會變成無限循環的二進位數。由於電腦無法儲存無限位數,浮點數必須捨去部分資訊,這就是浮點數不精準的原因。經典案例是 0.1 加 0.2 不等於 0.3,這在 Python、JavaScript、Ruby 都一樣,因為各語言都遵循 IEEE 754 規範,並非程式語言的問題。

407 - 位元運算

04 : 55

Python 內建的 bin() 函數可將整數轉換為二進位表示,例如 bin(100) 得到 0b1100100bin(7) 得到 0b111。反過來,int() 函數加上第二個參數 2,可將二進位字串轉回整數,如 int('111', 2) 得到 7。另外,二進位還有位元移位運算:向右移位 >> 會讓數值減半(如 25 >> 1 得到 12),向左移位 << 則讓數值加倍。這是因為二進位每多一位就是乘以 2,少一位就是除以 2。這些概念平常寫網站或爬蟲較少用到,但了解原理還是有幫助的。

408 - 不是數字的 NaN

07 : 24

NaN 是 IEEE 754 規範中的特殊浮點數,代表「不是數字」(Not a Number)。它本身是浮點數,但用來表示無法計算的結果。用 float('nan') 可以建立 NaN,透過 type() 檢查會顯示它是 float 型別。NaN 像黑洞一樣,任何加減乘除運算結果都還是 NaN。不過它仍遵守某些數學規則:任何數的零次方是 1,1 的任何次方是 1。NaN 最特別的地方是它不等於任何東西,包括自己,所以無法用等號判斷。要檢查某值是否為 NaN,必須使用 math.isnan() 函數。

409 - 無限大

08 : 45

Python 的浮點數有個特殊值叫無限大(inf),這是 IEEE 754 規範定義的概念,不是具體數值。當浮點數超過 sys.float_info 的最大值(約 10 的 308 次方)時,就會變成無限大,不會像整數超過 4300 位數那樣報錯。可以用 float('inf')float('-inf') 建立正負無限大。無限大的運算遵循數學邏輯:任何數加減乘無限大還是無限大,正無限大加負無限大會得到 NaN,因為這無法計算。無限大也遵守數學規則,例如零次方等於 1。可用 math.isinf() 判斷是否為無限大。

410 - 字串與跳脫符號

08 : 52

字串是程式語言中常見的資料型態,在 Python 裡可用單引號或雙引號包起來,兩者效果相同,官方建議選一種風格一致使用即可。當字串內容包含引號時,可用另一種引號包覆,或使用反斜線跳脫字元。反斜線有特殊用途:\"\' 表示普通引號、\n 表示換行、\t 表示 Tab 縮排。若需要在字串中顯示反斜線本身,則用 \\ 來跳脫。這些跳脫字元讓我們能在字串中表達各種特殊字元。

411 - 多行文字

04 : 11

Python 字串必須寫在同一行,換行會造成語法錯誤。若需要多行文字,可用三個連續的單引號或雙引號包起來,中間就能自由換行,常用於撰寫文件內容。有些教學資料會說這是「多行註解」,但這是錯誤的觀念。Python 並沒有多行註解,只有單行註解,就是井字號。三引號包起來的內容本質上是多行文字,只是沒有指派給變數,所以執行後沒有效果。Python 編譯時甚至會直接丟掉這些沒被使用的多行文字,根本不會編進程式碼裡。

412 - 字串型別轉換

04 : 50

Python 提供 str()int()float() 等函數做型別轉換,例如 str(18) 會把數字轉成字串。但這些函數名稱不是保留字,可以被當作變數名稱使用。如果你寫了 str = "hello",原本的 str() 函數就會被覆蓋掉,之後再呼叫 str(123) 就會出錯。同樣的情況也發生在 printlistint 等內建函數上。雖然語法上允許這樣命名,但一旦覆蓋就無法在該範圍內使用原本的功能。這個設計確實不太理想,但 Python 就是這樣,所以變數命名時要特別小心,避免使用這些內建函數的名稱。

413 - 字串與數字

07 : 59

Python 中數字和字串是不同型態,不能直接相加,但字串可以乘以數字來達到重複效果,例如 A * 3 會得到 AAA。字串之間可以用加號串接,甚至省略加號也能自動合併,但這種設計容易造成程式碼難以閱讀,尤其在串列中忘記加逗號時不會報錯卻產生非預期結果。若要將數字與字串組合輸出,必須先用 str() 函數轉換型態,不過這種寫法較繁瑣。更好的做法是使用 %s 格式化或 format() 方法,後者透過大括號挖洞、再填入變數的方式,寫起來更直覺易讀。

414 - 好用的 F 字串

13 : 14

Python 3.6 之後推出的 f 字串是格式化字串的簡便寫法,只要在字串前加上 f,就能用大括號直接嵌入變數。f 字串還有許多實用功能:用冒號加逗點可自動在千位數加上分隔符號;用 .2f 可指定小數位數;用百分比符號會自動乘以 100 並加上 % 符號。此外,f 字串支援欄位寬度設定,可指定靠左、靠右或置中對齊,也能自訂填充字元。最實用的是補零功能,例如 08d 會自動將數字補足 8 位數,處理時間格式時特別方便。這些功能在其他語言可能需要另外寫函數,但 f 字串一行就能搞定。

415 - 字串的索引值

04 : 20

索引用來從字串或串列中取得特定位置的元素,使用中括號加上索引值來存取。Python 的索引從 0 開始計算,所以 message[0] 會拿到第一個字元,message[1] 拿到第二個。若要取得最後一個元素,可以用負數索引,-1 代表最後一個,-2 代表倒數第二個,這樣不管字串多長都能輕鬆取得尾端資料。如果索引值超出範圍,Python 會直接拋出 index error,而不是回傳空值或 undefined。我很喜歡這種設計,有問題就明確告知,而不是默默給一個模糊的答案讓你自己判斷。

416 - 字串是不可變更的

02 : 30

Python 的字串是不可變的(immutable),無法透過索引直接修改其中的某個字元。嘗試用 message[0] = "t" 這種方式換掉字元會直接報錯。相較之下,JavaScript 的字串同樣不可變,但執行相同操作時不會報錯,只是靜靜地不生效,這種設計容易讓人誤以為修改成功。Python 的設計哲學是:既然不允許,就明確告訴你錯誤,而非讓你以為操作成功卻沒有實際效果。如果需要修改字串內容,只能整個字串重新賦值,無法單獨替換中間的字元。

417 - 為什麼索引值從 0 開始算?

04 : 54

索引值從 0 開始算是有原因的。字串或串列在記憶體中是連續存放的,每個格子有固定寬度。要取得某個元素,公式是「起始位置 + 索引值 × 寬度」。第一個元素不需要移動就能取得,所以索引值是 0;第二個元素要移動一格,索引值就是 1,依此類推。索引值其實就是「偏移值」(offset),代表相對於起始位置移動了幾格。不過並非所有程式語言都從 0 開始,像 Fortran、R 語言、Excel 都是從 1 開始,因為數學統計習慣如此。但 Python、Ruby、PHP 這些受 C 語言影響的程式語言,都習慣從 0 開始計算。

418 - 字串切片

03 : 27

切片(slice)是從字串或串列中取出一段資料的方法,語法是 [起始:停止:步長],三個位置用冒號分開。起始是開始的索引位置,停止是結束位置但不包含該位置的元素,步長是每次移動的距離。例如 [0:2:1] 從索引 0 開始取到索引 2 之前,每次走一格。[2:8:2] 則是從索引 2 到 8,每次跳兩格。步長可以是負數,表示反向取值,例如 [8:3:-1] 是從索引 8 往回走到索引 3。切片在 Python 中非常常用,字串和串列都適用這個語法。

419 - 切片省略部份欄位

12 : 14

Python 切片語法可以省略部分欄位來簡化寫法。兩欄式寫法中,省略開始位置預設為 0,省略結束位置則取字串長度,所以 [:] 可以複製整個字串。三欄式寫法較複雜,省略的欄位會根據 step 的正負號決定是左邊界值或右邊界值,這與兩欄式的預設值不同。例如 step 為負數時,省略開始位置會從右邊界開始,省略結束位置會到左邊界,這就是為什麼 [:5:-1][None:5:-1] 結果不同。切片只是複製該段內容,不會修改原字串。為了提高可讀性,可以用 slice() 函數建立切片物件並給予有意義的名稱。

420 - 常用的字串方法

15 : 24

Python 字串提供許多實用方法,像 upper、lower 可轉換大小寫,capitalize 讓首字大寫,swapcase 則交換大小寫。要注意這些方法不會改變原字串,因為 Python 字串是不可修改的,只會回傳新字串。比對方法包括 startswith、endswith 判斷開頭結尾,以及 isupper、islower 判斷大小寫。搜尋方面,index 和 find 都能找出字元位置,差別在於找不到時 index 會報錯,find 則回傳 -1。由於 -1 是有效索引值,使用時要特別注意情境。replace 可取代字串內容,strip 能去除頭尾空白。split 用指定符號拆解字串成串列,join 則反過來組合。這些方法在處理爬蟲資料時特別實用。

421 - Unicode 與 UTF-8

05 : 43

位元組(byte)與編碼是程式設計中重要的基礎概念。早期的 ASCII 編碼只用 7 個位元,僅能表示 128 個字元,對英文來說夠用,但無法涵蓋中文、日文等其他語言。各國因此發展出自己的編碼方式,如日本的 Shift_JIS、台灣的 Big5,但這導致網頁常出現亂碼問題。為解決這個困境,Unicode(萬國碼)誕生了,從最初的 16 位元擴充到現在的 20 位元,能容納全世界各種語言和 emoji。UTF-8 則是 Unicode 最常見的編碼實作方式,現在大多數瀏覽器和網站都預設使用它。

422 - 字串與位元組

13 : 25

位元組(byte)是 Python 3 新增的內建資料型態,在字串前加上 b 即可建立。雖然位元組看起來像字串,但本質不同:用索引取值會得到 ASCII 編碼數字,而非字元本身。中文字無法直接放入位元組,需透過 encode() 編碼、decode() 解碼,預設使用 UTF-8。重要觀念是:我們存入電腦的並非字串,而是位元組。編輯器會自動幫我們編解碼,所以才能看到文字。若編解碼方式不一致,就會出現亂碼。Python 2 的 byte 等同字串,但 Python 3 兩者完全不同,這也是兩版本不相容的原因之一。

第 5 章:布林值與流程控制

01 : 32 : 50

501 - 布林值

05 : 50

布林值是 Python 中的真假值,只有 True 和 False 兩種結果,注意開頭字母必須大寫,小寫會出錯。布林值的型態是 bool,是 boolean 的縮寫。比較特別的是,在 Python 中布林值其實是一種數字,True 等於 1,False 等於 0,所以可以進行數學運算,例如 True + True * 2 - False + True 會得到 4。雖然這樣設計有點奇怪,但知道這個特性即可,實際開發時不建議這樣寫。另外要注意 bool 不是保留字,如果拿來當變數名稱會覆蓋掉原本的功能,造成後續使用上的問題。

502 - 真的值、假的值

02 : 49

布林值可以做型別轉換。在 Python 裡,我們無法列出所有會轉成 True 的值,因為數量無限多,任何大於零的數字、任何字串都會轉成 True。但我們可以列出哪些是 False,其餘全是 True。會被轉成 False 的值包括:False 本身、None(代表沒有)、數字 0、空字串,以及空的容器如空串列、空 tuple、空字典。簡單來說,看起來「沒有」的東西都會是 False。要注意 Python 只有 0 是 False,負數如 -1、-2 都會轉成 True,這點跟某些程式語言不同。

503 - 布林值是一種數字

03 : 27

布林值本質上是數字,可以用 int()float() 轉換,True 會變成 1,False 變成 0。在 Python 中做數值比較會得到布林值,例如 1 < 2 回傳 True。一個等號是指定,兩個等號是比較,Python 不像 JavaScript 有三個等號的嚴格比較。有趣的是,Python 之父 Guido 早期設計 ABC 語言時,單一等號就是比較的意思,後來為避免混淆才改用兩個等號。因為 True 等於 1、False 等於 0,所以 1 == True 會成立,甚至可以用布林值當索引值取得字串元素,但這種寫法很怪,沒特殊目的不建議使用。

504 - 邏輯運算 Not, And, Or

02 : 31

Python 的邏輯運算主要有三種:not、and、or。and 代表「而且」,兩邊都要成立結果才會是 True;or 代表「或」,只要其中一邊成立就會是 True;not 則是把結果反過來,True 變 False,False 變 True。這些運算結果可以用真值表(truth table)來查詢,但寫久了自然就會記住。另外要注意運算優先順序,在沒有括號的情況下,not 優先權最高,其次是 and,最低是 or,就像數學的先乘除後加減一樣,計算時需要特別留意。

505 - 邏輯短路

03 : 56

Python 的邏輯短路是指在執行 and 或 or 運算時,如果前面的條件已經能決定最終結果,後面的運算就會直接跳過。以 and 來說,前面是 False 的話,後面不管怎麼樣結果都是 False,所以直接放棄運算。or 則相反,前面是 True 就不用看後面了。這個機制可以應用在效能最佳化上,把比較耗費 CPU 資源的運算放在後面,如果前面條件不成立,後面就不用白費力氣執行,節省運算資源。

506 - 位元運算

03 : 25

Python 的位元運算使用單一 & 符號,與邏輯運算的 and 不同。位元運算會將數字轉換成二進位後逐位比較,例如 10(1010)與 12(1100)做 & 運算,因為 & 要求兩邊都為 1 才得 1,所以結果是 1000,也就是十進位的 8。布林值 TrueFalse 本質上是 1 和 0,也能參與位元運算。True & False 得到 FalseTrue | False 得到 True。要特別注意,Python 的邏輯運算用 notandor,而單一 &| 是位元運算,兩者意義不同。

507 - if 流程控制

09 : 23

Python 中的流程控制使用 if 語法,例如判斷年齡是否大於等於 18 來決定是否印出訊息。條件後面要加冒號,小括號可省略。Python 的縮排是強制規定,不是慣例,因為沒有大括號來區分程式區塊,必須靠縮排判斷哪些程式碼屬於 if 內部。縮排不正確會直接報錯,無法執行。縮排可用空白或 Tab,數量不限,但同一區塊必須對齊。社群慣例是用四個空白。巢狀 if 就繼續往內縮排。這種強制規範能避免程式碼雜亂無章,我個人蠻喜歡這種設計。

508 - 什麼也不做的 pass

01 : 40

Python 因為使用縮排來定義程式區塊,所以在 if 等結構中必須寫點東西,不能留空。註解不算程式碼,無法用來佔位。如果暫時不知道該寫什麼,可以用 pass 這個關鍵字來卡位,它本身不做任何事,純粹讓程式結構完整。雖然技術上放任何值如 1 或 2 也能通過,但看起來很奇怪且語意不明。不過如果經常需要用 pass,應該反思一下為什麼不知道要寫什麼,畢竟寫程式時應該清楚自己的目的。

509 - if 與 else

02 : 54

Python 的條件判斷除了 if 之外,還有 else 和 elif。else 代表「不然」,當 if 條件不成立時執行,但 else 不是必要的,有 if 不一定要有 else,但有 else 一定要有 if。如果需要超過兩條路徑,可以用 elif(注意不是 else if,沒有空格也沒有 s 和 e)。例如判斷年齡:大於等於 20 歲可以選總統,大於 18 歲可以考駕照,其他情況走 else。在 if-elif-else 結構中,一定會走到其中一條路,elif 可以加很多個,想加幾個就加幾個。記得每個區塊都要縮排整齊。

510 - 《練習》閏年判斷

07 : 55

閏年判斷是學習流程控制的經典練習題。判斷邏輯是:先看是否為 4 的倍數,不是就是平年;是的話再看是否為 100 的倍數,不是就是閏年;是的話再看是否為 400 的倍數,是就是閏年,不是就是平年。用取餘數運算子 % 判斷倍數關係,若 year % 4 == 0 表示是 4 的倍數。根據流程圖,用巢狀的 if-else 結構逐層判斷,搭配 input() 取得使用者輸入並用 int() 轉型。這段邏輯也能簡化成一行:4 的倍數且不是 100 的倍數,或是 400 的倍數,就是閏年。先求寫得出來,再求精簡。

511 - 剪刀、石頭、布!

11 : 14

剪刀石頭布遊戲的實作方式是這樣的:先用 input() 取得使用者輸入的 1、2、3 分別代表剪刀、石頭、布,接著用 int() 轉換型別。判斷輸入是否在有效範圍內後,透過 random 模組的 randint(1, 3) 讓電腦隨機出拳。比較邏輯是:雙方相同就平手,再用多個條件判斷誰贏誰輸。另外有個偷吃步的做法,因為電腦出什麼對使用者來說是黑箱,所以可以直接用隨機數決定輸贏結果,完全不需要真的比較,但這種做法在需要顯示雙方出拳內容時就不適用了。

512 - switch 語法?

01 : 45

Python 沒有 switch 語法,這是官方刻意的設計。在其他程式語言或資訊課程中,當 if else 很多時,教科書通常建議改用 switch 或 case 來讓結構更整齊。但 Python 作者認為 switch 沒那麼必要,直接寫一堆 if else 就好。事實上,很多程式語言的 switch 本質上就是一堆 if else 而已。雖然沒有 switch,但 Python 有個叫 match 的功能,比其他語言的 switch 更好用、更強大。至於為什麼沒有 switch,Python 社群討論後認為不需要,if else 寫法已經夠清楚了。

513 - 三元運算子

03 : 53

Python 有類似其他語言三元運算子的寫法,但語法不太一樣。JavaScript 用問號和冒號,Python 則是把 if 放在值的後面,例如 message = "成年" if age >= 18 else "未成年"。這種寫法剛開始看會不太習慣,雖然只要一行比較簡短,但簡短不代表容易懂。另外還有用 and/or 邏輯短路的寫法,或是把布林值當成 0 和 1 的索引來取值,這些寫法雖然合法也能得到正確答案,但我個人不建議使用,因為可讀性不好,我自己還是習慣用標準的 if else 來寫。

514 - match

04 : 58

Python 3.10 新增了 match 語法,用起來類似其他語言的 switch,但功能更強大。原本處理多重條件判斷只能用一連串 if-else,現在可以用 match 搭配 case 來比對,程式碼看起來更有結構。match 背後是用雙等號做比對,最後一個 case 可以放任意變數名稱來接住其他情況,效果等同 else。如果不需要用到那個變數,可以用底線 _ 表示不在乎。整體來說,match 讓多重條件判斷的可讀性稍微提升,但也不算是非常巨大的升級。

515 - pattern matching

11 : 04

Python 的 match 語法不只是簡單的字串比對,它支援結構化模式比對(Pattern Matching)。首先,它可以比對型別,直接在 case 後面放型別如 int、float、str,省去使用 type() 檢查的步驟。更厲害的是結構比對,當資料結構符合指定模式時,會自動將對應位置的值指定給變數,不需額外宣告。不在意的值可用底線表示。這功能也適用於字典,可同時比對固定值和擷取變數。case 後面還能加 if 條件做進一步判斷,也支援用星號一次取得剩餘所有元素。這已經超越傳統 switch case 的功能了。

516 - 虛無飄渺的 None

02 : 32

None 在 Python 中是一個特殊的值,用來表示「沒有」或「不存在」。這聽起來有點哲學,因為我們其實無法真正知道什麼東西不存在,一旦你知道它,它就已經存在了。就像 NaN 本身是個數字卻代表「不是數字」一樣,None 也是一個存在的值,用來代表不存在的概念。None 的首字母必須大寫,它的型別是 NoneType,自成一派,跟 True、False 的布林型態類似。使用方式很簡單,直接指定給變數即可,例如 girlfriend = None 就表示這個變數沒有值。其他語言可能用 Null 或 Undefined,但 Python 統一用 None 來表達這個概念。

517 - == 與 is

03 : 54

Python 中比較運算有兩種方式:==is== 比較的是值是否相同,is 則比較是否為同一個物件。例如兩個內容都是 [1, 2, 3] 的串列,用 == 比較會得到 True,但用 is 比較會得到 False,因為它們是兩個獨立的物件,只是內容相同。就像網購買了兩箱一樣的東西,內容相同但就是兩箱。若寫成 a = [1, 2, 3]b = a,這時 ab 指向同一個物件,用 is 比較就會是 True。可用內建函式 id() 查看物件的記憶體位置,is 本質上就是比較兩者的 id 是否相同。

518 - String Interning 機制

07 : 04

Python 中 == 比較的是值是否相同,is 比較的是否為同一個物件。兩個內容相同的字串用 == 比較會是 True,但用 is 比較結果可能出乎意料。Python 的字串是不可變的,為了效能考量,內部會建立一個表格來暫存常用字串,當你使用相同字串時,Python 會讓你共用同一個物件。不過這個機制有限制:只有較短且僅包含英文字母、數字、底線的字串才會被暫存,含有空格等其他字元就不會。數字也有類似機制,但只有 -5 到 256 之間的整數會被預先建立並共用,超過這個範圍就會產生新物件。這些設計都是為了提升執行效能。

519 - 你是不是 None?

02 : 36

判斷某個值是否為 None 時,雖然可以用 == 比較,但官方建議使用 is。原因有二:首先,Python 中 None 是唯一的單例物件,用 is 比對更精準。其次,== 運算子實際上會呼叫物件的 __eq__ 魔術方法,而這個方法可以被覆寫。例如自定義類別若將 __eq__ 改成永遠回傳 True,即使物件明明存在,用 == 與 None 比較仍會得到 True,造成判斷錯誤。因此為了避免這種潛在問題,建議一律使用 is Noneis not None 來進行判斷。

第 6 章:迴圈

01 : 07 : 03

601 - for 迴圈

06 : 52

迴圈是用來處理重複性工作的程式結構。當需要印出多次內容或處理不確定數量的資料時,手動複製貼上不切實際,這時就需要迴圈。Python 有兩種迴圈:for 迴圈和 while 迴圈。for 迴圈使用 for ... in ... 語法,會依序從串列中取出每個元素。例如 for hero in heroes,每次迭代都會把一個元素指派給變數。命名很重要,如果集合是複數名稱如 heroes,迴圈變數就用單數 hero,這樣程式碼可讀性較佳。若暫時不知道迴圈內要做什麼,可用 pass 佔位。

602 - 範圍 range

04 : 14

range 函數可以產生一個數值範圍,例如 range(1, 11) 會產生 1 到 10 的範圍,注意結束值 11 不包含在內。range 本身不是陣列,而是一種惰性的資料結構,在你真正需要之前不會展開成具體的串列,這樣可以節省記憶體。如果需要轉成串列,可以用 list() 函數轉換。這是 Python 3 的設計考量,Python 2 會直接展開成陣列,這也是兩個版本不相容的原因之一。如果只給一個參數如 range(10),預設從 0 開始,產生 0 到 9 的範圍。

603 - 迭代 iteration

02 : 00

Python 的 for in 迴圈會進行「迭代」(Iteration),也就是一個一個把元素取出來的過程。Python 有很多可迭代物件,包括串列和字串。字串本身也是可迭代物件,例如把 Hello Kitty 放進 for in 迴圈,就會逐一取出 H、E、L、L、O 這些字元。for in 後面只要放可迭代物件就能運作,不限定只能用串列或字串,甚至自己定義的物件也可以做到,相當有彈性。

604 - for 迴圈的變數範圍

03 : 34

Python 的 for 迴圈有個需要注意的特性:迴圈變數可能會污染外層同名變數。例如外層已有 number = "hello kitty",若 for 迴圈寫成 for number in range(10),迴圈結束後外層的 number 會被覆蓋成 9。更特別的是,在迴圈內宣告的變數,離開迴圈後依然可以存取,這在其他語言中通常不允許。這種設計容易造成變數命名衝突,但透過函式和模組的封裝可以避免污染問題,等學到變數作用域(scope)時會更清楚如何處理。

605 - 列舉 enumerate

07 : 28

在 for 迴圈中若需要索引值,可以使用 Python 內建的 enumerate() 函數。傳統做法是在迴圈外宣告計數器變數,每跑一圈就遞增,但這樣寫法較笨拙。enumerate() 能將串列轉換成帶有索引的格式,每個元素會變成 (索引, 值) 的組合。使用時可以在 for 迴圈中同時接收兩個變數,一個是索引,一個是元素值。預設索引從 0 開始,但可以透過第二個參數指定起始值,例如 enumerate(heroes, 1) 就會從 1 開始編號。這種寫法更符合 Pythonic 風格,程式碼也更簡潔易讀。

606 -《練習》九九乘法表

04 : 45

九九乘法表是練習雙層迴圈的經典題目。外層迴圈用 for i in range(1, 10) 產生 1 到 9,內層再用 for j in range(1, 10) 做第二層迭代。透過 f-string 格式化輸出 f"{i} x {j} = {i*j}",其中乘號和等號只是裝飾用的字串,真正的運算是 i*j。工程師寫多層迴圈時,習慣用 i、j、k、l 依序命名變數,這是因為 i 可能代表 index 或 integer,而後續字母就順著往下取,算是一種不成文的慣例。

607 -《練習》聖誕樹

08 : 52

印出聖誕樹是經典的 Python 練習題。最簡單的半邊聖誕樹只要用 for 迴圈,讓星號乘以迴圈變數 i 就能印出 1、2、3、4、5 顆星的遞增效果。進階版要印出置中對齊的三角形,星星數量是 1、3、5、7、9,規律是「2 乘以 i 減 1」。前面要補空白讓圖形置中,空白數量則是「5 減 i」的遞減規律。寫迴圈最重要的是先找出規律,找到規律後程式碼自然就能寫出來。另一個更簡潔的做法是利用 f-string 的置中對齊功能,指定寬度後加上 ^ 符號就能自動置中,不用手動計算空白數量。

608 - 迴圈也有 else?

07 : 14

Python 的 for 迴圈可以搭配 else 使用,但這個 else 跟 if else 的「否則」不同。for else 的 else 區塊只有在迴圈「順利走完」時才會執行,所謂順利走完是指過程中沒有被 break 中斷。如果迴圈中途遇到 break 跳出,else 區塊就不會執行。這個語法在某些情況下很實用,例如檢查字串中是否存在特定字元。不過這個設計容易讓人困惑,因為 else 更像是「no break」的意思。Python 之父 Guido 也曾表示,如果能重來,他不會這樣設計。

609 - while 迴圈

06 : 01

while 迴圈用 while 關鍵字搭配條件判斷,只要條件成立就會持續執行。如果直接寫 while True,程式會無限循環,必須按 Ctrl+C 才能中斷。要避免無窮迴圈,必須在迴圈內加入控制機制來改變條件。例如設定 i = 0,條件為 i < 10,每次迴圈讓 i += 1,當 i 達到 10 時條件不成立,迴圈就會結束。實務上常見的寫法是設定一個狀態變數,在迴圈過程中根據某些條件改變它,讓迴圈能在適當時機停止。

610 -《練習》猜數字

07 : 00

猜數字遊戲是個經典的 while 迴圈練習。程式會用 random 模組的 randint 產生 1 到 100 的隨機整數作為答案,然後用 input 讓使用者輸入猜測。因為不知道何時會猜對,所以用 while 迴圈持續詢問,只要使用者的答案與正確答案不相等就繼續執行。每次猜測後會判斷數字太大或太小,給予提示讓玩家縮小範圍。要注意 input 回傳的是字串,必須用 int 轉型才能正確比較數值。用對半切的策略,因為 2 的 7 次方是 128,理論上 7 次內就能猜中。

611 - 迴圈的流程控制

07 : 12

迴圈裡有兩種流程控制:break 和 continue。break 會直接中斷整個迴圈,例如在 while True 的無限迴圈中,當條件符合時用 break 跳出。這種寫法等同於把終止條件放在 while 判斷式中,像猜數字遊戲就能用 break 在猜對時結束迴圈。continue 則是跳過本次迭代,直接進入下一輪,例如想印出偶數時,判斷如果是奇數就 continue,程式不會往下執行 print,而是回到迴圈開頭處理下一個數字。continue 比較像「下一位」的概念,不是繼續往下執行。這兩個關鍵字在 for 和 while 迴圈都適用。

612 - for 迴圈還是 while 迴圈

01 : 51

for 迴圈和 while 迴圈都能重複執行任務,但使用情境不同。while 迴圈適合在不確定要執行幾次的情況下使用,概念是「跑到跑不動為止」,例如跑操場但不知道要跑幾圈。for 迴圈則適合在明確知道執行次數時使用,例如要印出 1 到 10,用 for 寫起來比 while 簡潔許多,不需要自己控制條件。簡單來說,條件明確時我傾向用 for 迴圈,條件不明確時則用 while 迴圈。不過這沒有絕對,只要熟悉兩者的用法,交換使用都沒問題。

第 7 章:串列

01 : 30 : 53

701 - 關於串列

04 : 43

串列(list)是 Python 中使用頻率很高的容器型資料形態,可以一次存放多個元素。想像一個藥盒,每格放不同天的藥,有順序性又能整包帶走,串列就是這樣的概念。寫法是用中括號括起來,元素之間用逗號分隔。雖然看起來很像其他程式語言的陣列,但串列不是陣列。Python 的串列不限制元素型態,數字、字串、甚至其他串列都能混著放,不像 Java 或 C 語言的陣列必須宣告固定型態。Python 其實另外有陣列,後面會再補充說明。

702 - 串列常見操作

06 : 49

len() 函數可以計算序列的長度,不只適用於串列,也能用於字串、bytes、tuple、range 等序列型別。索引值從 0 開始,負數索引則從尾端往回數,例如 -1 取得最後一個元素。若索引超出範圍,Python 會拋出錯誤訊息。透過索引不僅能取值,還能直接賦值來替換元素。巢狀串列就像大腸包小腸,串列中可以再放串列,形成多層結構。要存取巢狀元素時,需依序使用多個中括號,例如 list[1][0] 取得第二層的第一個元素。若要遍歷巢狀串列,可用雙層迴圈逐一印出所有內容。

703 - 元素是否存在?

05 : 54

要判斷元素是否存在於串列中,最直覺的方式是使用 in 關鍵字,它會直接回傳 True 或 False,適用於多種資料結構。另一個方法是 index(),可取得元素的索引值,但若元素不存在會拋出 ValueError。還有 count() 方法能計算元素出現次數,若為 0 表示不存在。不過要注意,用 index() 做判斷有陷阱:當元素在索引 0 的位置時,因為 0 在布林判斷中等於 False,會導致判斷錯誤。因此單純判斷元素是否存在,建議優先使用 in,語法簡潔且結果明確。

704 - 新增、移除元素

09 : 45

使用 for 迴圈搭配複數命名的串列變數,可以清楚地逐一印出所有元素,while 迴圈雖然也能達成,但需要額外的計數器變數,寫起來較繁瑣。新增元素方面,append 方法可在串列尾端加入單一元素,extend 則能一次加入整個串列的內容。若要插入特定位置,insert 方法的第一個參數指定索引值,第二個參數是要插入的值,把索引設為 0 就能達到 prepend 的效果。移除元素可用 pop 方法,不帶參數會移除最後一個元素,帶索引值則移除指定位置的元素,並回傳被移除的值。remove 方法則是依據值來移除,但一次只移除第一個符合的元素,若要移除所有相同的值需搭配迴圈。當串列為空或找不到元素時,Python 會明確拋出錯誤。clear 方法可清空整個串列。

705 - 排序、反轉、合併

13 : 47

Python 串列的 sort() 方法會直接修改原本的陣列,如果不想改變原資料,可以改用內建函式 sorted(),它會回傳新的排序結果。兩者都支援 reverse=True 來做反向排序。透過 key 參數可以自訂排序依據,例如用 len 依字串長度排序,或傳入自訂函式計算排序權重。join() 方法則能將串列元素用指定符號串接成字串,比用 for 迴圈手動組裝更簡潔。查閱官方文件時,要注意參數型別,像 sorted() 和 join() 接受的是「可迭代物件」,代表不只能用在串列,字串等其他型別也適用。

706 - 可迭代物件

06 : 15

可迭代物件是指能夠逐一取出內部元素的物件,像是字串、串列、元組、字典等都屬於這類。只要物件內部實作了特定方法,就能成為可迭代物件,甚至可以自己定義。Python 有許多內建函式能處理可迭代物件,例如 sum 可計算總和,但要注意不能混入非數字的元素。any 函式只要有一個元素為 True 就回傳 True,all 則要全部為 True 才成立。enumerate 能為可迭代物件加上索引值,但回傳的是惰性物件,需要用 list 展開才能看到內容。查閱文件時,只要參數標示 iterable,就能傳入任何符合規格的可迭代物件。

707 - 同一個串列?

05 : 34

B = A 這樣寫時,A 和 B 會指向同一個串列,用 is 判斷會回傳 True。這意味著透過 A 修改內容時,B 也會跟著變動。若想讓兩個串列獨立,可以用 A.copy() 複製一份,這樣修改 A 就不會影響 B。但要注意 copy() 只做淺層複製,僅複製表層元素,若串列內還有巢狀結構,內層仍指向相同物件。若需要完整獨立的副本,要用 copy 模組的 deepcopy() 函式做深層複製。另一種方式是用 list(A) 建立新串列,效果類似淺層複製。

708 - 切片

02 : 22

切片在陣列的操作方式跟字串幾乎一樣,都是用中括號加冒號來指定範圍。但最大的差異在於:字串是不可變的,只能讀取不能修改;陣列則可以直接改動元素。例如有個陣列 ABCDE,用 0:2 可以取出 A 和 B,而且我還能把這兩個位置換成 123,原本的 A、B 就會被取代。同樣地,用 3:6 取出 C、D、E 後,也能直接換成 45。這就是陣列切片最強大的地方,不只能把東西拿出來,還能直接替換成想要的內容,這是字串做不到的。

709 - 串列推導式

07 : 06

串列推導式(list comprehension)是 Python 中重要且常用的語法,用於資料轉換。它的運作方式是將一堆資料經過處理後,產生另一堆資料,無法無中生有。語法格式為中括號內包含 for 和 in,例如 [n * 2 for n in range(5)] 會產生 [0, 2, 4, 6, 8]。相較於傳統 for 迴圈需要先建立空串列再逐一 append,串列推導式能用一行程式碼達成同樣效果,更為簡潔。後面的可迭代物件可以是 range、串列等,前面則是對每個元素的處理結果,最終收集成新串列。

710 - 小心!巢狀物件的坑

04 : 41

乘號可以用來重複串列元素,例如 [0] * 3 會得到三個 0。但這裡有個陷阱:用 [[]] * 3 產生的三個空串列其實指向同一個物件,修改其中一個,其他的也會跟著變。這是因為乘號做的不是真正的複製,而是讓多個位置指向相同的東西。如果需要獨立的空串列,應該用串列推導式 [[] for _ in range(3)] 來產生。同樣的問題也出現在巢狀串列相加時,例如 a = [[1,2,3]]a + a 產生的兩個元素其實是同一個物件。這個坑在面試或特殊情況下可能會遇到,要特別留意。

711 - 加上條件判斷

03 : 15

串列推導式可以對元素進行操作,例如將字串中的每個字元轉成大寫後收集成新串列。基本語法是中括號內包含 for in 迴圈,前面放要收集的結果,後面接可迭代物件。進階用法可加入條件判斷,在 for in 後面加上 if 條件,只有符合條件的元素才會被收集。例如從 1 到 10 中篩選偶數,用「if number % 2 == 0」判斷能否被 2 整除。這種寫法跟數學集合表示法概念相似,結果在前、條件在後、迴圈在中間。一行程式碼就能完成原本需要 for 迴圈加 if 判斷再 append 的多行寫法。

712 - 多層串列推導式

03 : 16

串列推導式可以寫成多層結構,像是用來產生九九乘法表。雙層推導式的寫法是在一個 for 後面再接一個 for,雖然可行但讀起來不太舒適,如果再加第三層就更難閱讀了。推導式有個好處是變數不會汙染外部作用域,在推導式裡定義的變數,外面拿不到。相較之下,for 迴圈裡的變數在迴圈結束後還能從外面存取,這可能造成變數汙染的風險。不過要注意,這是 Python 3 的行為,Python 2 的推導式變數還是會外洩到外部。

713 - 串列開箱!

08 : 32

串列開箱(unpacking)是 Python 實用的語法,可將可迭代物件中的元素直接指派給多個變數,省去逐一用索引取值的步驟。只要變數數量與元素數量對應,就能一次完成指派。若數量不符,Python 會明確報錯,不像 JavaScript 那樣給 undefined 或忽略。使用星號(*)可接收剩餘元素,例如取頭尾時中間用 *_ 接住不需要的部分。Python 夠聰明,星號不必放最後也能正確分配。還能做巢狀開箱,從複雜資料結構中精準取值。此語法適用於所有可迭代物件,包含字串與 Tuple,是 Python 3 之後的特性。

714 - 開箱運算子

04 : 05

序列開箱(unpacking)在 Python 中應用廣泛。變數交換 x, y = y, x 之所以能運作,是因為右邊其實是個 tuple,透過開箱機制將值分別賦予左邊的變數。同樣地,for i, hero in enumerate(heroes) 也是開箱操作,從每個 tuple 中取出索引與元素。星號(*)作為開箱運算子,除了收集剩餘元素外,還能展開序列。例如 [*range(5)] 可將 range 物件展開成串列,效果等同於 list(range(5))。這個技巧也能組合不同型態的可迭代物件,像是串列、字串、tuple 和 range,只要分別用星號展開再以中括號包起來即可。另外還有雙星號(**)專門用來開箱字典。

715 - 《冷知識》Python 的陣列

04 : 49

Python 的串列不是陣列,陣列是另一種資料型態,需要 import array 模組才能使用。使用陣列時必須先宣告型別,例如 i 代表整數、f 代表浮點數、u 代表 Unicode,宣告後只能放入相同型別的資料。這樣的設計是為了效能考量,因為固定型別讓記憶體配置更有效率,可以透過索引值快速取得元素。Python 的陣列與傳統陣列不同,雖然不能混放型別,但長度可以動態調整,支援 append 和 insert 等操作。雖然陣列效能較好,但串列使用更直覺方便,所以實務上大多還是使用串列。

第 8 章:字典

01 : 02 : 26

801 - 建立字典

07 : 04

字典是 Python 中常用的資料結構,由 key 和 value 配對組成,外層用大括號包覆。相較於串列,字典能為資料加上標籤,讓內容更容易理解,例如用 name、level、power 等 key 來標示對應的值。建立字典有兩種方式:使用大括號字面值,或使用 dict() 函式。效能上,大括號寫法較佳,因此若無特殊需求建議優先使用。dict 類別還提供 from_keys() 方法,可快速用可迭代物件建立字典,未指定值時預設為 None,也可傳入第二個引數設定所有 key 的預設值。

802 - 取用字典

06 : 12

字典取值方式跟串列類似,但因為字典沒有順序,所以用 key 而非索引值來取值。如果 key 不存在會拋出 KeyError。為了避免錯誤,可以用 in 判斷 key 是否存在,或用 get() 方法取值,拿不到會回傳 None,也能設定預設值。另外還有 setdefault() 方法,當 key 不存在時會新增該 key 並設定值,若已存在則回傳原本的值。雖然 setdefault() 也能取值,但我個人偏好用 get(),因為語意更清楚直覺。

803 - 字典沒有順序?

02 : 19

Python 3.6 之前,字典使用雜湊表實作,因為雜湊值無法預測大小順序,所以字典內容的排列順序是不確定的。但從 3.6 版本開始,字典會保留 key 的加入順序,先加入的會排在前面。不過這裡說的「有順序」只是指排列上有順序,實際存取時仍然無法用索引取值,還是得透過 key 來取得對應的值。如果需要真正支援索引的有序資料結構,可以使用串列或 Tuple。

804 - 新增、更新字典

02 : 40

字典的新增或更新操作很簡單,使用 key 加上等號即可。例如要把 name 從「地球人」改成「火星人」,直接指定 key 並賦值就完成了。讀取時若 key 不存在會出現 KeyError,但設定時若 key 不存在,Python 會自動新增這組 key-value,不會報錯。除了逐一更新,也可以用 update 方法一次更新多筆資料。update 會將新字典的內容合併到原字典,已存在的 key 會被覆蓋,不存在的則新增。不過 update 這名字有點誤導,因為它實際上比較像合併而非單純更新,使用前要確認這是你要的效果。

805 - 有這個 Key 嗎?

02 : 33

要判斷字典裡有沒有某個 key,可以用 in 關鍵字,簡單直覺。另外還有個 __contains__ 方法也能達到相同效果,會回傳 True 或 False。這種雙底線開頭的方法在 Python 中很常見,因為英文是 double underscore,簡稱 dunder,所以叫 dunder method,又稱為魔術方法。不過這些魔術方法通常是給系統內部呼叫用的,例如當我們使用 in 關鍵字時,Python 內部其實就是去呼叫 __contains__。所以一般情況下,建議直接用 in 這種簡潔的寫法就好,除非你很清楚自己在做什麼,否則不需要直接呼叫魔術方法。

806 - Key 的限制?

02 : 56

字典的 key 必須是不可變的資料型態,例如字串、數字、布林值和 tuple。布林值 True 等於 1,所以用 True 當 key 時,也能用 1 取值。數字可以當 key,雖然寫成 0、1、2 看起來像陣列,但本質仍是字典,沒有順序概念,不能用 -1 存取。tuple 因為不可變,也能當 key 使用,例如用座標 tuple 對應城市名稱。但如果用串列當 key 會出錯,因為串列是可變物件,Python 會回報 unhashable type 錯誤。簡單來說,能當 key 的東西必須是可被雜湊的不可變物件。

807 - 為什麼叫字典?

02 : 57

Python 的字典(Dictionary)命名其實有其道理。字典這個資料結構在其他語言有不同稱呼,像是雜湊(Hash)、關聯陣列,或 JavaScript 的物件。Python 選擇「字典」這個名稱,是因為它能直觀表達 key 與 value 的一對一對應關係,就像查字典時每個單字對應一個解釋。雖然 Python 字典底層是用雜湊表實作,但若直接叫 hash 容易與雜湊函式或雜湊值混淆。而 JavaScript 叫物件也有問題,因為陣列也是物件,容易造成混淆。相較之下,「字典」這個命名清楚表達了 key-value 的配對特性,是個相當好的設計選擇。

808 - 字典常見操作

07 : 07

Python 字典可以用 len() 函式計算有幾組 key-value 配對。clear() 方法會清空整個字典內容,而 del 關鍵字可刪除指定的 key,但要小心別誤刪整個字典。取出並移除元素可用 pop() 方法,需指定 key,若 key 不存在會報錯,但可設定預設值避免錯誤。popitem() 方法則會取出最後一組 key-value 配對,Python 3.6 之後字典按照插入順序排列,採用 LIFO 原則,最後放入的最先被取出。透過 while 迴圈搭配 popitem() 可逐一取出所有元素,直到字典變空為止。

809 - 合併字典

04 : 28

Python 字典合併有幾種方式。第一種是使用雙星號開箱運算子,將兩個字典展開後用大括號包起來,例如 {**dict1, **dict2},這種寫法簡潔直覺。第二種是透過 dict() 函式,將一個字典作為參數,再用雙星號展開另一個字典作為關鍵字引數傳入。第三種是使用 OR 運算子 |,直接寫 dict1 | dict2,但這是 Python 3.9 之後才支援的語法。不論哪種方式,當兩個字典有重複的 key 時,後面的會覆蓋前面的,因此 a 合併 b 和 b 合併 a 的結果可能不同,使用時須留意順序。

810 - 複製字典

03 : 18

當 A 等於某個字典,B 等於 A 時,兩個變數會指向同一個字典,改其中一個另一個也跟著改。為避免這情況,可以用 copy 方法複製一份新字典,讓兩者各自獨立。但 copy 只能複製第一層,遇到巢狀結構時,深層內容仍會互相影響。這時要用 copy 模組的 deepcopy 函式做深層複製。另外也可以把字典丟給 dict() 函式,或用兩個星號做開箱來複製,但這些同樣只能複製淺層。簡單的淺層複製我習慣用 copy 方法,深層複製則只能靠 deepcopy。

811 - 印出所有 Key 跟 Value

06 : 47

字典的 keys()、values() 和 items() 方法可以分別取出所有的鍵、值,以及鍵值配對。items() 會回傳 tuple 組合,搭配 for 迴圈和開箱語法很方便。這三個方法回傳的都不是串列,而是特殊的 view 物件,這是為了效能考量,避免大型字典一次載入佔用大量記憶體。view 物件是惰性的,需要時才取值。有趣的是,這個 view 像是一扇窗戶,當原始字典內容改變時,透過它看到的結果也會跟著變動,不需重新呼叫方法。另外,因為字典的 key 不會重複,dictkeys 物件可以做集合運算如交集聯集,而 dictvalues 則沒有這個特性。

812 - 字典推導式

04 : 49

串列有串列推導式,字典也有字典推導式,兩者都用於資料轉換。字典推導式使用大括號,且因為字典由 key 和 value 組成,寫法中間需要加上冒號。例如用 {x: x**2 for x in [1,2,3,4,5]} 可以產生以數字為 key、平方為 value 的字典。若要將兩個串列合併成字典,可以使用內建的 zip() 函式,它像拉鍊一樣把兩個串列配對成一組一組的 tuple。配合字典推導式就能輕鬆轉換成字典。更簡潔的做法是直接把 zip() 的結果丟進 dict() 函式,連推導式都不用寫就能得到相同結果。

813 - 什麼是「雜湊」?

09 : 16

雜湊函式(hash function)能將任意長度的資料轉換成固定長度的字串,這個結果稱為雜湊值。雜湊函式的特點是輸入與輸出有固定對應關係,相同輸入必定產生相同輸出,但只要輸入差一個字,結果就完全不同,這叫做雪崩效應。因此雜湊常用來驗證檔案是否被竄改。雖然不同輸入可能產生相同結果(稱為碰撞),但機率極低。Python 的 hash() 函式可進行雜湊計算,但只有不可變物件才能被雜湊,串列、字典等可變物件無法計算。字典的 key 必須是可雜湊物件,若兩個物件的雜湊值相同,作為 key 時後者會覆蓋前者。

第 9 章:元組與集合

00 : 56 : 43

901 - 建立 Tuple

07 : 54

Tuple 是 Python 中常用的資料型態,發音可念 Tuple 或 Tuple,連 Python 之父 Guido 也說隨意。建立 Tuple 使用小括號,元素用逗號分隔,也可用 tuple() 函式轉換可迭代物件。Tuple 與串列最大差異在於不可變動,一旦建立就無法修改內容,特性上更接近字串。若 Tuple 只有單一元素,後面的逗號不可省略,否則會被當成一般數值。小括號在某些情況可省略,但逗號才是決定 Tuple 的關鍵。遇到運算式時,省略小括號可能造成語意混淆,建議保留以提高可讀性。

902 - Tuple 常見操作

05 : 36

tuple 跟陣列一樣有順序,可用索引值取得元素,從 0 開始,也支援負數索引。但 tuple 是不可變的資料型態,無法修改裡面的元素。使用 += 看起來像修改,其實是產生新的 tuple 再重新指定,這叫 reassign。tuple 支援 for in、len、count、index 等操作,但 append、insert、remove 這些破壞性操作都不行。要注意的是,如果 tuple 裡面放了可變物件如陣列或字典,那個物件本身還是可以修改的,這種 tuple 就不是可雜湊物件,不能當字典的 key。選擇 tuple 主要不是效能考量,而是不可變性帶來的安全性,資料傳遞時不怕被意外修改。

903 - 複製 Tuple

04 : 12

tuple 跟串列一樣可以複製,但 tuple 沒有 copy 方法,只能用 tuple() 函式、copy 模組或切片來做。不過這裡有個重要觀念:tuple 的複製其實不是真的複製,而是指向同一個物件。用 is 判斷會發現複製前後是同一個東西。為什麼這樣設計?因為 tuple 是不可變的資料結構,既然內容不能改,複製一份只是浪費記憶體。但要小心,如果 tuple 裡面包含可變物件(如串列),改動該物件的內容,原本的 tuple 也會受影響,這點操作時務必注意。

904 - 空的 Tuple?

04 : 45

建立空的 tuple 很簡單,直接用小括號 () 或呼叫 tuple() 函式即可。空的 tuple 有個有趣特性:不像一般 tuple,即使分別建立兩個空 tuple,用 is 比較會發現它們是同一個物件。因為空 tuple 無法新增或修改內容,Python 為了節省記憶體,讓所有空 tuple 都指向同一個物件。實務上很少用到空 tuple,可能的用途是當函式需要維持回傳型別一致性時,找不到資料就回傳空 tuple,而非 None 或 False。不過我個人不太堅持這點,回傳 None 通常就夠了。

905 - Tuple 的效能

03 : 56

tuple 跟串列相比,效能確實好一些。用 timeit 模組測試,同樣內容跑 1000 萬次,tuple 比串列快,但差距大約只有 0.3 秒,所以效能不會是選擇 tuple 的主要理由。記憶體使用上,tuple 也比串列省。原因在於串列是可變動的,Python 會預留額外的 capacity 當作 buffer,避免每次新增元素都要重新尋找更大的連續記憶體空間。tuple 因為不可變動,不需要預留空間,所以佔用的記憶體較少。整體來說,tuple 在效能和記憶體使用上都優於串列,但選擇 tuple 的理由通常不會只是效能考量。

906 - Tuple 推導式?

04 : 42

Python 的小括號推導式語法看起來像 Tuple 推導式,但實際上會產生一個 generator(產生器),而非 Tuple。產生器可以用 for 迴圈遍歷,也能用 next() 函數逐一取值,取完後會拋出 StopIteration 錯誤。若需要真正的 Tuple,可將產生器轉型。至於串列和 Tuple 的選擇,我的建議是:確定內容不會變動就用 Tuple,會變動就用串列。效能差異在一般應用中影響不大。另外根據官方文件的風格建議,同質性資料(如全是數字)適合用串列,異質性資料(混合不同型別)則適合用 Tuple,但這只是慣例而非硬性規定。

907 - 集合

05 : 43

集合(set)是 Python 內建的資料型態,有兩個重要特性:元素不會重複,且沒有順序。建立集合可用大括號或 set() 函式,放入可迭代物件即可。若有重複元素會自動過濾,但轉換後順序不保證與原本相同。集合常用於去除重複元素,例如將串列轉成集合再轉回來。要注意集合只能存放可雜湊物件,像串列這種可變動的資料就無法放入。有個有趣的冷知識:因為 NaN 不等於自己,所以集合中可以存在多個 NaN,看起來像是有重複元素,但這只是特例,實務上不會這麼用。

908 - 集合常見操作

06 : 58

集合是一種可迭代物件,可以用 for 迴圈遍歷,但要注意集合沒有順序,每次迭代的順序可能不同。如果需要順序,應該使用 tuple 或串列。集合可以新增、修改、刪除元素:用 add 新增元素,用 remove 刪除元素,但刪除不存在的元素會產生 key error。為了安全刪除,可以先用 in 判斷元素是否存在,或使用 discard 方法,即使元素不存在也不會報錯。用 clear 可以清空集合。建立空集合不能用空的大括號 {},因為那會產生空字典,必須用 set() 來建立。複製集合可以用 copy 方法或 set() 函數,但因為沒有順序,無法使用切片複製。

909 - 交集、聯集、差集

04 : 21

集合除了不重複、無順序的特性外,還支援交集、聯集、差集等數學運算。交集使用 & 符號或 intersection() 方法,取得兩集合共同的元素。聯集使用 | 符號或 union() 方法,合併所有元素但不重複。差集使用 - 符號或 difference() 方法,從一個集合減去與另一個集合重疊的部分。交集和聯集沒有順序性,但差集有,因為 A 減 B 和 B 減 A 結果不同。此外,isdisjoint() 方法可判斷兩集合是否有交集,回傳布林值。

910 - 嚴格子集

03 : 25

集合有子集合(subset)與超集合(superset)的概念。以 {1,2,3,4,5} 和 {2,3,4} 為例,後者的元素都包含在前者中,所以 {2,3,4} 是 {1,2,3,4,5} 的子集合,反過來則是超集合。Python 提供 issubset() 和 issuperset() 方法來判斷這種關係。另外還有「嚴格子集」(proper subset)的概念,條件是元素必須都被包含,但兩個集合不能完全相等。例如 {1,2,3} 是 {1,2,3,4} 的嚴格子集,但 {1,2,3,4} 對自己就只是子集合而非嚴格子集。這些數學概念在實際寫程式時不常直接用到,可當作複習數學。

911 - 集合推導式

03 : 04

集合推導式的寫法是用大括號包住單一元素,例如 {n for n in range(5)}。要注意的是,如果大括號內放的是 key-value 組合,產生的會是字典而非集合,因為這兩種資料結構共用相同的符號。另外有個冷知識:如果集合裡不小心放了 nan,用 remove() 是拿不掉的,因為 nan 無法跟自己比較相等。解決方法是透過推導式過濾,利用 item == item 這個條件,因為只有 nan 不等於自己,就能把它濾掉。不過實務上很少會遇到這種情況。

912 - 冷凍集合

02 : 07

Frozen Set(冷凍集合)是 Python 中一種特殊的集合型態。由於大括號、小括號、中括號都已被其他資料型態使用,建立冷凍集合只能透過 frozenset() 函式,傳入可迭代物件即可。冷凍集合與一般集合最大的差異在於它是不可變動的,就像 Tuple 一樣,無法使用 add()remove()clear() 等方法來新增或刪除元素。也因為不可變動的特性,冷凍集合是可雜湊物件,理論上可以當作字典的 Key 使用,雖然實務上這種情境相當少見。

第 10 章:函數(基礎篇)

02 : 22 : 04

1001 - 什麼是函數?

06 : 30

函數是輸入值與輸出值之間的對應關係,就像國中數學的 f(x) = 3x + 2,帶入不同的 x 會得到對應的結果。寫函數的主要目的不是為了重複使用,而是把程式碼抽象化,賦予一段邏輯一個有意義的名稱。即使函數只用一次也值得寫,因為好的函數名稱能讓人一眼看懂這段程式碼想做什麼,不需要閱讀內部實作細節。重複使用只是函數的副產品,真正的價值在於讓程式碼更具可讀性。命名時要避開保留字和內建函數名稱如 list、str、int 等。

1002 - 定義函數

05 : 50

定義函數使用 def 關鍵字,後接函數名稱、小括號和冒號。函數內的程式碼必須縮排,這是 Python 的強制規定,用來標示程式碼區塊的範圍。不像其他語言用大括號區隔,Python 靠縮排來判斷哪些程式碼屬於同一區塊,沒縮排或縮排錯誤會直接報錯。執行函數時要在名稱後加小括號,否則不會執行。函數命名應該清楚表達用途,例如 say_hellohi 更好理解。縮排不只是為了美觀,更是讓程式碼有結構、易閱讀的重要習慣。

1003 - pass

03 : 29

Python 的函數或類別定義若內容為空會造成語法錯誤,因為 Python 強制要求縮排區塊必須有內容。註解不算程式碼,所以無法用來佔位。雖然放數字、字串或 None 都能通過語法檢查,但語意上不太恰當。Python 為此設計了 pass 這個關鍵字,它本身不執行任何動作,純粹用來卡位。當我們定義函數、類別或 if-else 區塊,但還不確定要寫什麼內容時,就可以用 pass 先佔住位置。不過也值得思考:如果連內容都還不知道,是否真的需要這麼急著把結構寫出來?

1004 - 參數

07 : 15

函數裡的 x 在程式中稱為「參數」(parameter),是定義函數時設定的變數名稱,用來接收傳入的值。參數命名要有意義,像 someone 比 ABC 更清楚。呼叫函數時帶入的值則稱為「引數」(argument),例如 say_hello(Kitty) 中的 Kitty 就是引數。Python 對參數數量要求嚴格,定義幾個就要帶幾個,多或少都會報錯,這點跟 JavaScript 不同。錯誤訊息會明確指出 missing argument 或 takes 0 but 1 was given,所以參數和引數雖常被混用,但其實是兩個不同概念。

1005 - 執行還是呼叫?

01 : 24

呼叫函數和執行函數這兩個詞的立場不太一樣。呼叫函數是指去請求、叫這個函數動起來;執行函數則是指函數運算的過程。也就是說,需要先呼叫才會執行,這兩個動詞代表不同的階段。不過對工程師來說,很多時候會混著用,反正意思知道就好,就是要讓函數動起來、帶東西給它這樣。

1006 - 關鍵字引數

07 : 37

Python 函數的參數設計可分為「位置引數」和「關鍵字引數」兩種。位置引數按順序傳入,一個蘿蔔一個坑,順序不能錯。關鍵字引數則用參數名稱指定值,例如 height=100, weight=200,好處是順序可以任意調換,不怕搞混。以計算 BMI 為例,若用位置引數,搞反身高體重會得到錯誤結果;改用關鍵字引數就能避免這問題。Python 內建的 print() 函數也用了關鍵字引數,像 sep 可改分隔符號、end 可改結尾字元。這兩種引數可以混用,讓函數設計更有彈性。

1007 - 位置引數與關鍵字引數

08 : 05

關鍵字引數使用時有幾個規則:位置引數必須放在關鍵字引數前面,否則會報錯。同一個參數不能帶兩次,不管是用位置引數還是關鍵字引數,重複帶值會出現錯誤訊息。若要限定參數的使用方式,可以用斜線和星號標記。斜線前面的參數只能用位置引數,星號後面的參數只能用關鍵字引數,中間的則不限制。以內建函數 sorted 為例,第一個參數只能用位置引數帶入,而 key 和 reverse 則必須用關鍵字引數。這樣的設計讓函數設計者能明確規範使用方式。

1008 - 參數預設值

04 : 43

Python 函數可以設定參數預設值,在定義參數時用等號指定預設值,呼叫時若未傳入該參數就會使用預設值。設定預設值的主要目的不是偷懶,而是讓函數使用起來更有彈性,常用的值設為預設,使用者可以不帶參數直接使用,也可以傳入自訂值來客製化。像 print() 函數就有多個預設參數,讓基本使用變簡單,同時保留客製化空間。但要注意,有預設值的參數必須放在沒有預設值的參數後面,否則會造成語法錯誤,這是 Python 的設計規則。

1009 - 參數預設值的坑!

08 : 00

Python 函數參數的預設值在定義時就已經決定,這是個常見的坑。如果預設值是 random.random() 這類函數呼叫,每次執行函數都會得到相同結果,因為該值在定義時就固定了。同樣地,若預設值是空串列等可變動物件,多次呼叫函數時會共用同一個物件,導致資料累積而非重新開始。解決方法是將預設值設為 None,進入函數後再判斷:若為 None 才建立新物件或呼叫函數。數字、字串等不可變物件作為預設值則沒有這個問題。

1010 - 不定數量參數之位置引數

08 : 10

Python 的 print 函數可以接受任意數量的參數,這是透過星號(*)語法實現的。在函數參數前加上星號,表示該參數會收集所有傳入的位置引數,並打包成一個 tuple。例如定義 def hi(*values),不論傳入一個、三個或十個引數都能處理。若函數同時有一般參數和星號參數,如 def foo(a, *b),則 a 先取得第一個值,剩餘的全部由 b 收集。當星號參數後面還有其他參數時,如 def foo(a, *b, c),由於星號會「吃掉」所有位置引數,後方的 c 就必須使用關鍵字引數的方式傳入,否則會產生錯誤。

1011 - 不定數量參數之關鍵字引數

03 : 41

Python 函數中,單星號(*)可以接收所有位置引數並收集成 tuple,但遇到關鍵字引數會出錯。要同時處理兩種引數,需搭配雙星號(**),它會把關鍵字引數收集成字典。常見寫法是 *args**kwargs,這組合能接收任意數量的位置和關鍵字引數。args 是 arguments 的縮寫,kwargs 是 keyword arguments 的縮寫,但這只是慣例命名,不是 Python 內建的特殊字,你可以用任何喜歡的參數名稱。

1012 - 引數開箱

04 : 40

Python 的星號有多種用途,其中一個是解包(開箱)功能。當函數定義了固定數量的參數時,可以用單星號將串列或 tuple 解開,自動對應到各個位置引數,省去逐一用索引取值的麻煩。但要注意元素數量必須與參數數量相符,否則會出錯。集合因為沒有順序,解包時順序可能不如預期。若要用關鍵字引數的方式傳入,可以用雙星號解開字典,此時字典的 key 必須與函數的參數名稱對應。單星號解開後是位置引數,雙星號解開後是關鍵字引數,兩者使用時都要確保數量和名稱正確匹配。

1013 - Docstring

05 : 36

在函數內第一行放置的字串稱為 Docstring(文件字串),這不是註解,而是用來說明函數用途的文字。使用三個引號可以撰寫多行說明,單引號或雙引號皆可。透過 help() 函數可以查看任何函數的 Docstring 說明,例如 help(print) 會顯示 print 函數的使用方式。函數物件有個特殊屬性 __doc__ 可以直接取得這段說明文字。Docstring 可放在模組、函數或類別中,目的是為程式碼加上文件說明,方便自己或他人理解如何使用。當不確定某個函數怎麼用時,除了 Google 或問 GPT,也可以用 help() 查看。

1014 - 回傳值

07 : 41

函數的回傳值是很重要的概念,很多新手容易把 print 和 return 搞混。print 只是在執行過程中把東西印在畫面上,但那不是函數的結果。當我們把參數丟給函數,應該要得到一個答案回來,這才是回傳值。在 Python 中,如果要讓函數有回傳值,必須明確寫出 return,否則函數執行完就是沒有結果,會得到 None。設計函數時,應該讓輸入值和輸出值之間的對應很明確,每個函數只要做好自己該做的事就好,例如 add 函數就專心算加法,把答案回傳就好,不需要負責印出來,印的工作交給 print 來做。

1015 - Early Return

06 : 39

return 不只是回傳值,更是將程式控制權交還給呼叫者。當函數執行到 return 時會立即結束,後面的程式碼都不會執行。若 return 後面沒有接任何值,Python 會自動回傳 None。利用這個特性可以使用 early return 技巧:在函數開頭先檢查參數是否合法,不合法就直接 return 結束。這樣可以省略 else,讓程式碼結構更清楚。

1016 - 所有函數都有回傳值?

02 : 55

Python 的函數即使沒有明確寫 return,也會回傳 None。所以「所有函數都有回傳值」這句話是對的,因為 None 本身就是一個實實在在存在的物件,只是用來代表「沒有」或「不存在」。這其實是個有趣的哲學問題:我們無法真正描述「不存在」,因為當你知道某個東西不存在時,就代表你已經知道它了。None 就像站在路邊舉著「這裡沒有人」牌子的人,它明明存在,卻用來表示不存在。不管是 None 還是 NaN,都是用一個存在的東西來描述「沒有值」這件事。

1017 - 函數是一等公民

07 : 12

Python 中的函數是「一等公民」(First-class citizen),意思是函數跟數字、字串、串列等資料型態一樣,都是可以丟來丟去的值。既然 123 可以指定給變數,函數當然也可以;既然字串可以放進串列,函數也行。這帶出「高階函數」的概念:只要一個函數能接收其他函數當參數,或是能回傳函數,就稱為高階函數。其實沒什麼神秘的,就是把函數當成一般物件看待而已。正因為函數是物件,所以可以用 __doc__ 取得文件字串,甚至能在函數物件上隨意新增屬性。不過並非所有程式語言都這樣設計,例如 Ruby 的函數就不是物件。

1018 - 作用域 LEGB 之 LEG

09 : 49

Python 變數有作用域(scope)的概念,決定變數在哪裡可以被存取。作用域分為四個層級,稱為 LEGB:L 是 local(區域),E 是 enclosing(外層函數),G 是 global(全域),B 是 built-in(內建)。當程式需要找某個變數時,會依照 LEGB 順序由內往外找:先找區域變數,找不到就往外層函數找,再找不到就找全域變數。值得一提的是,enclosing 這層設計是 Python 2.2 版才加入的,在那之前函數內的函數會直接跳過外層函數去找全域變數。

1019 - 作用域 LEGB 之 B

06 : 50

Python 的變數查找遵循 LEGB 規則:先找 Local(區域),再找 Enclosing(外層函數),接著 Global(全域),最後才是 Built-in(內建)。以 print 為例,當程式執行時會依序在這四個範圍尋找,直到找到為止。這也解釋了為什麼 list、str、int 這些內建函數可以被覆寫,因為它們的優先順序最低。如果你在某個範圍內定義了同名變數,就會「攔截」內建函數。不過這不代表完全不能用這些名稱,只要確定該範圍內不會呼叫到原本的內建函數,就不會有問題。理解 LEGB 規則後,就能清楚知道變數會在哪裡被找到,避免命名衝突造成的錯誤。

1020 - a = a + 1

10 : 42

Python 函數內的變數賦值行為有特殊規則。當在函數裡寫 A = 2 這樣的賦值語句時,Python 會將它視為「宣告區域變數」,而非修改外層變數。這是為了避免意外覆蓋外部變數。因此,若在函數內寫 A += 1,等號左邊會宣告區域變數 A,但等號右邊卻要讀取尚未賦值的 A,導致錯誤。Python 會先將程式碼編譯成 bytecode,此時變數已存在於該 scope 中,只是尚未賦值。即使賦值寫在後面,該變數仍會被視為區域變數,因此無法按 LEGB 規則往外層查找。這個規則需要特別注意。

1021 - global 與 nonlocal

10 : 55

Python 中變數的作用域遵循 LEGB 規則。當需要在函數內修改全域變數時,可使用 global 關鍵字,宣告後該變數就會指向最外層的全域變數。若是巢狀函數想存取外層函數的變數,則使用 nonlocal 關鍵字,它只會往上層函數尋找,不會跳到全域範圍。兩者的差異在於:global 直接指向最外層全域變數,nonlocal 則是逐層往外找,但止於函數範圍,不會觸及全域。由於 Python 的變數宣告與賦值語法相同,透過這些關鍵字才能明確區分「宣告新變數」與「修改既有變數」的意圖。

1022 - 函數 vs 方法

04 : 21

方法(Method)和函數(Function)在 Python 裡都是用 def 關鍵字定義的,本質上都是函數,但使用方式不同。方法必須透過物件來呼叫,例如 numbers.sort() 是對 numbers 這個物件呼叫 sort 方法;而函數可以直接呼叫,例如 sorted(numbers) 是把串列當參數傳入。兩者雖然都能排序,但行為不同:sort() 方法會直接修改原本的串列,sorted() 函數則會回傳一個新的排序後串列,不會動到原本的資料。方法通常定義在類別裡面,跟著物件走,這部分在物件導向章節會有更詳細的說明。

第 11 章:函數(進階篇)

01 : 53 : 11

1101 - 表達式 vs 陣述句

09 : 34

表達式(expression)和陳述句(statement)是程式語言中的基本概念。表達式像是單字或片語,例如數字 18、字串 Hello Kitty 或比較運算 1450 > 9527,它們都會產生一個結果。陳述句則是完整的句子,像 cat = 5if cat > 0,本身不會有結果。一個陳述句通常由多個表達式組成,就像人類語言中一句話由多個單字片語組成。if、for、while、def、class 這些關鍵字都屬於陳述句。理解這個區別對於後續學習 lambda expression 會有幫助,也能更容易看懂其他人寫的進階程式碼。

1102 - Lambda 表達式

06 : 09

表達式(expression)與陳述句(statement)是理解 lambda 的基礎。lambda 是希臘字母,在 Python 中用來建立匿名函數。一般定義函數用 def,但無法像 JavaScript 那樣在宣告變數時同時定義函數。lambda 解決了這個問題,語法是 lambda 參數: 表達式,例如 add = lambda a, b: a + b。關鍵是冒號後面必須是表達式,不能放 return 這類陳述句,否則會語法錯誤。lambda 可以不帶參數,像 lambda: 1lambda: None,雖然沒什麼實用價值,但語法上是合法的。使用時跟一般函數一樣,加小括號傳入參數即可。

1103 - Lambda 表達式的限制與使用

10 : 23

Lambda 表達式只能包含一個表達式,不適合複雜計算,否則程式碼會變得難以閱讀。Lambda 裡面不能做賦值,因為賦值是 Statement 而非 Expression,這會造成語法錯誤。同樣地,型別註記也無法在 Lambda 中使用。Lambda 的參數用法和一般函數相同,可設定預設值、使用關鍵字引數,也能用星號收集位置引數或關鍵字引數。Lambda 常見的應用場景是搭配 sorted 的 key 參數、map、filter 等函數使用。它的優點是不用想名字、只用一次就丟棄,語法也較精簡。不過因為 Python 有串列推導式,我自己用 Lambda 的機會其實不多。

1104 - Closure 之自由變數

07 : 14

在函數內宣告的區域變數,執行完後就會消失,直接存取會出現「未定義」錯誤。若想讓函數記住變數又不想用 global 污染全域,可以使用 closure(閉包)這種程式設計手法。在介紹閉包前,先認識「自由變數」:當內層函數使用到外層函數的變數時,該變數對內層函數而言就是自由變數。每個函數都有 __code__ 屬性,其中的 co_freevars 可查看該函數的自由變數有哪些。這只發生在 enclosing 情況,全域變數不算。理解自由變數的概念後,接下來就能學習如何透過閉包把變數「帶著走」。

1105 - Closure 之變數帶著走

04 : 54

在函數內定義的區域變數,照理說函數執行完就會消失。但閉包打破了這個規則。當一個函數回傳另一個內部函數時,內部函數會把它用到的變數「帶著走」。即使外層函數已經執行完畢,內部函數仍然可以存取那些變數。這些被帶走的變數叫做「自由變數」,不受一般 scope 規則限制,可以在程式中持續存在,直到程式結束為止。閉包讓變數的生命週期延長,能在不同地方被引用或使用。

1106 - Closure 之運作原理

07 : 54

Python 的閉包透過 Cell Object 機制實現。當某個變數被多個不同的 scope 參照時,Python 會自動建立 Cell Object。例如外層函數的變數 A 若被內層函數使用,這兩處的 A 都會指向同一個 Cell Object,再由 Cell Object 指向實際的值。這就是閉包能「記住」外層變數的原因:當外層函數執行完畢,區域變數雖然消失了,但 Cell Object 仍然存活。內層函數實際上是指向 Cell Object 而非已消失的變數,所以依然能存取該值。透過 __code__.co_cellvars 可查看哪些變數成為 Cell Object,而 __closure__ 屬性則能取得閉包中的 Cell Object 內容。

1107 - Closure 之應用

03 : 56

閉包可以用來建立私有變數,避免全域變數過於開放而被意外修改。由於閉包會記住環境中的自由變數,我們可以利用這個特性製作計數器。實作方式是定義一個外層函數,在裡面宣告 count 變數並初始化為 0,接著定義內層函數,使用 nonlocal 關鍵字標註 count,讓內層函數能存取外層的變數並進行遞增。每次呼叫 create_counter 都會產生一個獨立的計數器,各自維護自己的狀態,互不干擾。這就是閉包的實用價值,而接下來要介紹的裝飾器,也是透過閉包原理實作出來的。

1108 - 函數裝飾器

08 : 34

函數裝飾器(Decorator)在 Python 中相當實用,特別是在 Flask 或 Django 網站開發時經常使用。裝飾器的核心概念是將一個函數傳入另一個函數,經過包裝後再回傳。以 deprecated 裝飾器為例,在內部定義一個 wrapper 函數,利用閉包原理保留原本傳入的函數,並在執行前加入警告訊息。當呼叫被裝飾的函數時,會先印出「此函數即將棄用」的提示,再執行原本的功能。重點在於回傳的是函數本身而非執行結果,等到實際呼叫時才會觸發整個流程。

1109 - 函數裝飾器的語法糖

02 : 01

Python 的 Decorator 裝飾器可以透過語法糖讓寫法更簡潔。語法糖的概念就像藥外面包了一層糖衣,吃起來比較順口,但本質沒變。原本使用裝飾器需要先把函數包起來再呼叫,寫法較囉嗦。Python 提供 @ 符號作為語法糖,只要在函數定義前加上 @decorator_name,就等同於原本的包裝寫法,兩者效果完全相同。這種寫法更簡潔好看,不用每次都手動包裝,在使用別人的套件或框架時特別常見且實用。

1110 - 函數裝飾器之原本的參數?

05 : 56

裝飾器要能重複使用,必須處理被裝飾函數可能有不同參數的情況。當被裝飾的函數需要參數時,原本沒有參數的 wrapper 函數會因為引數數量不符而出錯。解決方法是在 wrapper 函數中使用 *args**kwargs,前者接收所有位置引數,後者接收所有關鍵字引數。wrapper 收到這些參數後,再原封不動傳給原本的函數執行。這樣不管被裝飾的函數有幾個參數、是位置引數還是關鍵字引數,裝飾器都能正常運作,達到真正可重複使用的目的。

1111 - 帶有參數的裝飾器

10 : 52

裝飾器可以帶參數,例如傳入一個理由說明為何棄用某功能。當裝飾器後面有括號帶參數時,代表這個裝飾器本身會回傳另一個裝飾器,形成「大層包小層」的結構。實作時需要多包一層函數:最外層接收參數(如 reason),內層才是真正接收被裝飾函數的 decorator。另一個問題是,當裝飾器不帶參數時會出錯,因為被裝飾的函數會被當成參數傳入。解法是用 callable() 判斷傳入的是函數還是字串,再做相應處理。Flask 的 @app.route() 就是這種帶參數裝飾器的實例。裝飾器寫起來燒腦,但用起來很方便。

1112 - 遞迴

05 : 01

遞迴是函數自己呼叫自己的技巧。當函數執行時會被放到 call stack(呼叫堆疊)上,執行完才移除。如果函數內又呼叫其他函數,新函數會疊上去,完成後再一層層移除。當遞迴沒有終止條件時,堆疊會不斷往上疊,但因為記憶體有限,疊滿就會發生 stack overflow(堆疊溢位),這也是知名程式問答網站 Stack Overflow 名稱的由來。Python 預設堆疊上限是 1000 層,超過就會拋出 recursion error。雖然可以透過 sys 模組調整上限,但若程式邏輯沒有出口,終究還是會滿出來。

1113 - 遞迴之費氏數列

08 : 40

費波納西數列是經典的遞迴範例,每一項等於前兩項的和。可以用迴圈實作:設定初始值 A=0、B=1,透過不斷交換並相加來產生數列。也可以用遞迴寫法:定義基底情況(第 0 項為 0、第 1 項為 1),其餘則回傳 fib(N-1) + fib(N-2)。遞迴寫法更接近數學公式,看起來簡潔漂亮,但要注意必須有出口條件,否則會造成 stack overflow。遞迴的本質是拆解問題,把大問題分解成小問題。雖然我蠻喜歡遞迴的設計,但實務上用迴圈的機會比較多。

1114 - 遞迴的效能?

03 : 37

遞迴寫法雖然優雅,但效能是個問題。以費波納西數列為例,當 N 逐漸增大時,遞迴會不斷分裂成更多子問題,堆疊數量呈指數成長。實測在 M1 電腦上,N 到 35 以上就明顯感覺到延遲。相較之下,迴圈寫法只是不斷交換變數,即使 N 等於 50 也瞬間算完。雖然有「尾遞迴呼叫」這種最佳化技巧可以改善效能,但 Python 本身不支援也不打算支援這個功能,所以學了也用不上。結論是,我個人喜歡遞迴的設計方式,但考量到 Python 的限制,處理較大數字或複雜程式時,還是會斟酌使用。

1115 - 產生器

11 : 29

Python 的 Generator(產生器)是一種惰性運算機制,使用 yield 關鍵字來實作。與一般函數用 return 直接回傳整個結果不同,yield 會暫時交出控制權並回傳一個值,下次呼叫時再從中斷處繼續執行。透過內建的 next() 函數可以逐一取值,像擠牙膏一樣分批獲取資料。當所有值都取完後會拋出 StopIteration,但 for 迴圈或串列推導式會自動處理這個例外。產生器的優勢在於不需要一次將所有資料載入記憶體,特別適合處理大量資料的情境,能有效節省記憶體使用量。

1116 - 偏函數與柯里化

06 : 57

偏函數(partial function)和柯里化函數(currying)都能實現「分期付款」式的參數傳遞。偏函數讓我先給部分參數,剩下的之後一次付清,Python 的 functools 模組已內建 partial 函數可直接使用。柯里化函數則是每次只傳一個參數,一次付一期,直到所有參數都給齊才執行函數並回傳結果。這兩個概念在一般網站開發或爬蟲工作中較少用到,但作為函數式程式設計的知識還是值得了解。

第 12 章:錯誤處理

00 : 24 : 35

1201 - 錯誤的種類

05 : 40

Python 裡常見的錯誤類型:SyntaxError 是語法錯誤,通常是括號或冒號寫錯;IndentationError 是 Python 特有的縮排錯誤;NameError 是變數或函數不存在,可能與作用域有關;TypeError 是型別錯誤,例如數字與字串相加;ValueError 是值的轉換錯誤;ZeroDivisionError 是除以零的錯誤;IndexError 是串列索引超出範圍;KeyError 是字典中找不到對應的 key;FileNotFoundError 是檔案不存在;AttributeError 是存取物件不存在的屬性。最後區分 Error 和 Exception 這兩個名詞,雖然常被混用,但實際上有所不同。

1202 - 錯誤 vs 例外

04 : 37

錯誤是比較廣泛的概念,包含語法錯誤等無法恢復的問題;例外則是程式本身沒問題,但執行過程中因外部因素(如使用者輸入零當分母)而產生的狀況,通常可以處理並恢復。不同程式語言對此有不同定義,像 Java 會在名稱加上 Exception 後綴來區分,但 Python 的設計較特別,雖然名稱多用 Error 結尾,但這些錯誤類別其實都繼承自 Exception,形成「錯誤是例外的子集合」這種獨特架構。不論是錯誤還是例外,工程師都必須想辦法處理這些問題。

1203 - 製作自己的錯誤類別

02 : 51

透過 raise 可以丟出 NameError 等內建錯誤,並自訂錯誤說明文字。雖然 Python 內建的錯誤類型已經夠用,但在較大型的專案中,建議自訂專屬的錯誤類別。做法是繼承 Exception 類別,例如建立 PokemonCardError,這樣當錯誤發生時,從錯誤名稱就能更清楚知道問題所在,像是「噴火龍卡片無法使用」這類專案專屬的錯誤訊息,比起一般的語法錯誤更容易理解和除錯。關於類別和繼承的概念,會在後續物件導向章節詳細說明。

1204 - 錯誤處理

06 : 52

當程式可能出錯時,例如除以零,可以用 try 把可能出錯的程式碼包起來,萬一出錯就跳到 except 區塊處理,程式不會直接當掉。不建議把所有程式都包進 try,因為身為工程師應該知道哪裡可能出錯。except 後面可以指定特定錯誤類型,例如 ZeroDivisionError 或 NameError,針對不同錯誤做不同處理。最後還可以加一個不指定類型的 except 當作最後防線,接住所有未預期的錯誤。這種做法跟 if/else 主動檢查不同,try/except 的概念是「先做再說,出錯再救」。

1205 - 錯誤處理之 finally 與 else

04 : 35

finally 區塊不論 try 成功或失敗都會執行,適合用來做收尾動作,例如關閉檔案或中斷資料庫連線。else 區塊則是在 try 沒有出錯時才會執行。完整組合為 try、except、else、finally。最後分享一個冷知識:當 try 區塊中有 return,finally 仍會優先執行,因此若 finally 中也有 return,最終會回傳 finally 的值。不過這種寫法不建議使用,僅供了解優先順序。下個章節將介紹 Python 的模組與套件。

第 13 章:模組與套件

01 : 20 : 29

1302 - 虛擬環境之模組搜尋路徑

02 : 15

1301 - 模組與套件

05 : 35

1303 - 建立、匯入模組

10 : 13

1304 - 只匯入部份功能

04 : 58

1305 - 重複匯入模組?

06 : 05

1306 - 匯入模組的位置

02 : 17

1307 - 匯入同名函數

05 : 33

1308 - 同名模組

05 : 34

1309 - 能有點隱私嗎?

03 : 14

1310 - 被匯入 vs 直接執行

05 : 52

1311 - 套件與模組的差異

08 : 45

1312 - __init__.py 的用途

05 : 26

1313 - 《冷知識》不同的套件

09 : 13

1314 - 《冷知識》壓縮檔也可以

05 : 29

第 14 章:物件導向程式設計(基礎篇)

02 : 45 : 18

1401 - 什麼是物件?

04 : 00

1402 - 建立物件

10 : 08

1403 - 初始化

11 : 47

1404 - 建構子?

04 : 37

1405 - 實體變數

03 : 40

1406 - 實體方法

06 : 54

1407 - 類別變數

06 : 03

1408 - 存取類別變數

13 : 48

1409 - Getter 與 Setter

08 : 56

1410 - 屬性裝飾器

10 : 35

1411 - 私有屬性?

05 : 11

1412 - 限定屬性存取之 Slots

10 : 57

1413 - 類別方法

10 : 04

1414 - 靜態方法

05 : 53

1415 - 繼承

12 : 11

1416 - 沒寫就沒有繼承嗎?

07 : 16

1417 - 方法覆寫與 super

11 : 19

1418 - 你是我的後代嗎?

09 : 39

1419 - 多重繼承

03 : 39

1420 - 多重繼承之鑽石問題

08 : 41

第 15 章:物件導向程式設計(進階篇)

02 : 06 : 04

1501 - 描述器

10 : 27

1502 - 資料描述器

09 : 56

1503 - 資料描述器可以幹嘛

06 : 30

1504 - 所以,值要存在哪裡?part 1

10 : 01

1505 - 所以,值要存在哪裡?part 2

05 : 19

1506 - 刪除屬性

04 : 08

1507 - 函數與方法

14 : 48

1508 - slots 其實也是描述器

06 : 05

1509 - Meta Class

09 : 39

1510 - 建立 Classs 的原始碼

05 : 29

1511 - 建構子?

08 : 25

1512 - 魔術方法

03 : 33

1513 - 魔術方法之物件看起來的樣子

11 : 56

1514 - 迭代器

11 : 46

1515 - 可迭代物件

08 : 02

第 16 章:檔案處理

00 : 28 : 23

1601 - 讀取檔案

09 : 19

1602 - 游標的位置

02 : 34

1603 - 用完記得關!

02 : 57

1604 - with 關鍵字

04 : 40

1605 - 寫入檔案

08 : 53

第 17 章:處理 CSV 檔案

00 : 50 : 27

1701 - 讀取 CSV 檔案

06 : 51

1702 - 設定方言(Dialect)

07 : 27

1703 - 寫入 CSV 檔案

05 : 07

1704 - 台積電股價 K 線圖 part 1

10 : 52

1705 - 台積電股價 K 線圖 part 2

09 : 44

1706 - 台積電股價 K 線圖 part 3

10 : 26

第 18 章:資料抓取與解析

01 : 03 : 10

1801 - 什麼是 API?

05 : 08

1802 - 抓取書局銷售排行資料 part 1

06 : 35

1803 - 抓取書局銷售排行資料 part 2

11 : 48

1804 - 從 API 抓取地震資料 part 1

04 : 48

1805 - 從 API 抓取地震資料 part 2

09 : 23

1806 - 從 API 抓取地震資料 part 3

09 : 10

1807 - 從氣象署網頁抓資料 part 1

07 : 52

1808 - 從氣象署網頁抓資料 part 2

08 : 26

第 19 章:偵錯工具

00 : 29 : 46

1901 - 使用 Pdb 偵錯器

07 : 34

1902 - 執行程式

09 : 03

1903 - 動態設定中斷點

05 : 37

1904 - 誰呼叫了這個函數?

02 : 58

1905 - Pdb 常用指令整理

04 : 34

PY101

為你自己學 Python

現在報名只要 NT$3,800
  • 終身存取權
  • 可行動裝置使用
  • 課程時長:25.4 小時
  • 結業證書

其他課程推薦