Python 已成為主流程式語言,廣泛應用於網頁後端、科學計算等領域。然而,許多開發者並未充分運用 Python 的所有功能。本文旨在探討 Python 語言和工具中一些較不熟悉的方面,例如非同步程式設計、套件管理和測試,並結合實際案例,幫助讀者更好地理解這些技術的應用場景。本文並非單純的技術參考手冊,而是透過構建一個真實的軟體專案——通用資料聚合器,將各項技術融入到實際的開發流程中,讓讀者在學習過程中更能體會技術選擇的考量因素。本文目標讀者是具備一定 Python 基礎,希望進一步提升程式設計能力的開發者。書中避免深入底層實作細節,著重於實務應用,即使不熟悉 C 擴充套件、元類別或演算法也能從中受益。
關於作者與技術審閱者
作者簡介
Matthew Wilkes 是一位歐洲軟體開發者,過去15年來一直使用Python從事網頁專案開發。除了開發軟體外,他在商業環境中指導Python開發人員方面擁有豐富經驗。同時,他也積極參與開源軟體開發,曾為多個流行的框架做出貢獻,尤其專注於網頁框架的資料函式庫和安全互動細節。
技術審閱者簡介
Coen de Groot
Coen de Groot是一位自由職業的Python開發者與培訓師,自1970年代末期接觸電腦和程式設計以來,便對此充滿熱情。他曾在大型石油公司、新創企業、軟體代理商等多個不同環境中工作,撰寫過許多不同程式語言的軟體,並曾參與軟體支援、培訓、團隊長官和技術專案管理。在IT行業工作約20年後,Coen轉行成為商業教練,並主持了一個大型教練社群,組織了五場會議。但不久後,他又被吸引回來為教練和其他人建立網站和其他IT服務。在過去的10年中,Coen主要使用Python進行程式設計,同時也涉及SQL、JavaScript等語言,並持續學習更多Python知識,並透過面對面教學、寫作或影片分享他的經驗。
Nejc Zupan
Nejc Zupan從小就是一個科技迷,在小學時期開發了他的第一個電腦遊戲,在高中時期贏得了全國機器人比賽冠軍,並在大學時期共同創辦了niteo.co。他曾在五大洲的會議上發表演講,主要內容與網頁、Python和生產力相關。只要他不寫程式,就會在世界各地追逐大浪。
Jesse Snyder
Jesse Snyder在多年延遲了民族音樂學的研究生學習後開始程式設計,並驚喜地發現自己完全沉浸在軟體設計的挑戰和回報中。在太平洋西北非營利科技界工作數年後,他現在是一名獨立顧問。當他不工作或演奏爪哇甘美蘭音樂時,很可能正在西雅圖家附近的美麗公園和社群進行長跑。
致謝
許多人以各種方式幫助了這本文的完成。首先必須感謝的是Python開源生態系統的數千名貢獻者;沒有他們,就不會有這本文。要感謝Joanna在面對困難和長時間工作時的鼓勵。也要感謝我的家人多年來堅定不移的支援。特別感謝Nejc Zupan、Jesse Snyder、Tom Blockley、Alan Hoey和Cris Ewing,他們對本文的計劃和實施提出了寶貴的意見。同時,也要感謝Mark Wheelwright在拍攝我的照片方面所做的出色工作,以及Apress團隊的辛勤工作。最後,要感謝那些繼續讓網頁變得像我第一次接觸網際網路時一樣奇妙的人們。Thomas Heasman-Hunt、Julia Evans、Ian Fieggen、Foone Turing等等 – 如果沒有你們這樣的人,我懷疑工業軟體不會吸引這麼多我的注意力。
Python 程式語言的進階應用與探索
Python 是一種極為成功的程式語言,在其存在的大三十年裡,已經變得非常普及。它預設搭載於主要作業系統上;世界上一些最大的網站都在後端使用 Python,科學家們每天都使用 Python 來推進我們集體的知識。由於有這麼多人每天都在開發和Python相關的工作,因此改進進展迅速。但並非所有 Python 開發者都有機會參加會議,或有時間跟進社群不同領域的工作,因此語言和生態系統中的某些功能並不如它們應有的那樣廣為人知。
本文的目的
本文的目標是檢視語言和 Python 工具中可能不是每個人都熟悉的部分。如果你是一位經驗豐富的 Python 開發者,你可能已經知道其中許多工具,但還有更多的工具可能在你的待辦清單上,等待你有時間時嘗試。這種情況尤其適用於那些正在開發既有系統的開發者,因為重新架構元件以利用新的語言功能並不是可以經常做的事情。
本文的結構與內容
本文並不是一本具有獨立章節的參考書,各章節之間的流程取決於我們如何構建一個真實的軟體。許多技術檔案都有提供簡單的範例。簡單的範例非常適合解釋某件事情是如何運作的,但對於理解何時使用它並不是那麼有用。它們也可能很難在其基礎上構建,因為複雜的程式碼往往與簡單的程式碼在架構上有很大的不同。
透過遵循這一個範例,我們能夠在上下文中考慮技術選擇。你將瞭解到在選擇特定方法時需要考慮哪些因素。與使用方式相關的主題將被一起涵蓋,而不是那些與工作原理相關的主題。
本文的目標讀者
我在撰寫本文時的目標是分享來自社群不同領域的知識,以及我在 15 年寫 Python 程式碼的經驗中所學到的教訓。它將幫助你在使用核心語言和附加函式庫方面提高生產力。你將學會如何有效地使用語言的功能,例如非同步程式設計、套件和測試。
然而,本文是針對想要寫程式碼的人,而不是那些希望瞭解深層魔法的讀者。我不會探討涉及 Python 實作細節的主題。你不需要了解 Python C 擴充套件、元類別或演算法就能從本文中受益。
範例程式碼與輸出
實質性的程式碼範例如編號清單所示,本文的附帶程式碼包括這些清單的電子版本。其中一些清單還直接在其下方顯示輸出,而不是單獨作為編號圖。本文附帶的程式碼也是您找到根據章節的完整程式碼函式庫副本的地方,以及練習的輔助程式碼。
範例:通用資料聚合器
本文的範例是一個通用資料聚合器。如果你從事 DevOps 工作,那麼你很可能使用類別似的程式來追蹤伺服器的資源利用率。或者,作為一名網頁開發者,你可能會使用類別似的東西來匯總來自同一系統的不同佈署的統計資料。一些科學家使用類別似的方法,例如匯總分佈在城市各地的空氣品質感測器的發現。它不是每位開發者都需要構建的東西,但它是許多開發者都熟悉的問題空間。
使用 Raspberry Pi Zero 進行範例演示
我將使用配備了一些售後感測器的 Raspberry Pi Zero 進行範例演示。這個平台廣泛可用,價格約為 5 美元,並提供了許多有趣的資料。有許多商業感測器附加元件可供選擇。
雖然我會推薦一些特定於 Raspberry Pi 的東西,以便更容易地遵循範例,但本文並不是關於物聯網或 Raspberry Pi 本身。它是一種達到目地的手段;如果你願意,你應該能夠輕鬆地調整範例以適應與你的興趣更相關的任務。前面提到的任何類別似問題都將遵循相同的設計過程。
主題選擇
本文所涵蓋的主題旨在闡明 Python 程式設計的不同方面。所有這些主題都是 Python 社群整體上未充分使用或未被充分理解的,並且沒有一個是初學者通常會學到的。這並不是說它們一定很複雜或難以理解(儘管有些確實如此),但它們是我認為所有 Python 程式設計師都應該熟悉的技術,即使他們選擇不使用它們。
章節簡介
第 1 章將向您介紹用 Python 編寫非常簡單的程式的不同方法,特別是將涵蓋 Jupyter notebook 和 Python 偵錯器的介紹。雖然這兩個工具都相對知名,但許多人熟練使用其中一個,但不熟悉另一個。本章還將介紹如何在 Windows 上使用類別似於 Windows Subsystem for Linux 的環境,因為大多數附加元件都是針對 Linux 或 macOS 系統編寫的,因此在 WSL 下可能表現更好。
本文內容導覽與技術重點解析
本文主要圍繞Python程式語言的高階技術與應用展開,從命令列介面開發到非同步程式設計、資料視覺化等主題進行探討。
章節概覽與技術亮點
第1章:命令列工具開發
本章節介紹如何撰寫命令列介面,並探討多個有用的第三方函式庫,以支援簡潔高效的命令列工具開發。透過實際案例與技術分析,讀者可學習到如何開發專業級的命令列應用。
第2章:程式碼品質保障工具
涵蓋自動化測試與程式碼檢查工具,幫助開發者識別並修正程式碼中的錯誤。這些工具對於維護大型程式碼函式庫或需要多人協作的專案至關重要。本章節著重於分析各工具的優缺點,幫助讀者做出明智的技術選擇。
第3章:Python程式碼封裝與依賴管理
探討Python程式碼的封裝與依賴分發機制,這些技術對於開發可分發的應用程式和設計可靠的佈署系統至關重要。讀者將學習如何將獨立指令碼轉換為可安裝的應用程式。
第4章:外掛架構設計
介紹外掛架構的設計原理,這是一種強大的軟體設計模式。本章節透過實際案例展示如何利用外掛架構提升應用程式的擴充性,並探討相關的進階命令列工具技術,以簡化除錯流程。
第5章:Web介面與進階函式技術
涵蓋Web介面的開發,以及裝飾器、閉包等進階函式技術。這些技術是Python程式設計中的慣用模式,但往往難以在其他程式語言中直接套用。本章節還討論了抽象基礎類別(ABC)的適當使用場景。
第6章:聚合伺服器與第三方函式庫應用
擴充套件範例應用,引入聚合伺服器元件,並展示多個實用的第三方函式庫,如「requests」。這些函式庫在日常Python開發工作中極為常見,能夠顯著提升開發效率。
第7章:執行緒與非同步程式設計
探討Python中的執行緒與非同步程式設計技術。執行緒往往是微妙錯誤的來源,而非同步程式設計雖然能夠解決類別似的問題,但其程式行為與同步程式設計有著顯著差異。本章節著重於實際應用中的平行程式設計,而非單純的技術演示。
第8章:非同步程式設計進階與測試
進一步探討非同步程式設計,涵蓋非同步程式碼的測試方法,以及用於處理外部工具(如資料函式庫)的函式庫。同時介紹了一些有助於編寫良好API的進階技術,如上下文管理器和上下文變數。
第9章:Jupyter中的資料視覺化與互動式應用
回到Jupyter環境,利用其強大的資料視覺化與互動功能。讀者將學習如何在Jupyter筆記本中使用非同步函式,並掌握迭代器和複雜資料型別的進階用法。
第10章:Python效能最佳化
詳細介紹如何透過不同的快取技術提升Python程式碼的效能,並探討適當的效能基準測試方法,以找出程式的效能瓶頸。
第11章:容錯機制設計
擴充套件前述概念,探討如何在外掛架構中無縫處理錯誤,同時保持向後相容性。本章節還深入分析了錯誤處理流程的設計原則。
第12章:迭代器與協程在資料分析中的應用
利用Python的迭代器和協程功能,增強儀錶板應用,使其能夠主動內省已收集的資料,從而建立多步驟分析流程。
Python版本支援與環境設定
本文範例根據Python 3.8版本進行測試,並相容於Python 3.9的早期開發版本。不建議使用較舊的Python版本,因為大部分範例在Python 3.7或3.6中可能無法正常執行。
為順利跟隨本文內容,讀者需要安裝Python pip。若Python已安裝,通常pip也已包含在內。某些作業系統可能會刻意移除pip,此時需透過作業系統的套件管理器進行安裝(如Debian-based系統中的sudo apt install python3-pip)。其他作業系統可使用python -m ensurepip --upgrade指令來安裝或升級pip。
本文的電子版範例程式碼及勘誤表可於出版社網站或本文官方網站(https://advancedpython.dev)取得。若讀者在學習過程中遇到問題,這些資源將是首要的參考依據。
Python 原型開發與環境探討
在 Python 專案開發過程中,無論是短期的幾小時專案還是長達數年的大型專案,原型開發都是不可或缺的一環。原型開發能夠幫助開發者快速測試函式功能並驗證想法。本文將探討不同的原型開發方法,並建立簡單的函式來提取資料,最後構建一個簡單的命令列工具。
Python 中的原型開發
在任何 Python 專案中,開發者都需要對函式進行原型開發。這可能是專案的第一步,也可能在專案中期才開始。不論何時,開發者最終都會在 Python shell 中嘗試程式碼。
原型開發有兩種主要方法:一種是執行一段程式碼並檢視結果,另一種是逐條執行陳述式並檢查中間結果。一般來說,逐條執行陳述式更為高效,但有時如果已經對某些程式碼段有信心,直接執行整段程式碼似乎更為方便。
使用 REPL 進行原型開發
REPL(Read, Eval, Print, Loop)是大多數人接觸 Python 的第一步。它允許開發者直接在直譯器中輸入命令並立即檢視結果,而無需編譯檔案。這種方式對於簡單程式的開發具有較低的延遲。
REPL 的優勢在於能夠快速測試簡單的程式碼,並直觀地理解函式的工作原理。然而,它對於涉及大量流程控制的任務並不友好,因為它對錯誤的容忍度較低。如果在輸入迴圈主體時出現錯誤,開發者需要重新開始,而不是僅僅編輯錯誤的行。
例如,當開發者不記得內建函式 filter(...) 的用法時,可以直接在 REPL 中嘗試:
>>> filter(range(10), lambda x: x == 5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'function' object is not iterable'
>>> filter(lambda x: x == 5, range(10))
<filter object at 0x033854F0>
>>> tuple(filter(lambda x: x == 5, range(10)))
(5,)
REPL 的侷限性
當嘗試在 REPL 中實作涉及更多流程控制的任務,如經典的 FizzBuzz 問題(清單 1-1),就會發現其侷限性。
for num in range(1, 101):
val = ''
if num % 3 == 0:
val += 'Fizz'
if num % 5 == 0:
val += 'Buzz'
if not val:
val = str(num)
print(val)
在 REPL 中逐步構建 FizzBuzz 程式時,開發者需要重複輸入之前已經輸入過的程式碼,這些程式碼無法編輯。一旦出現錯誤,整個迴圈需要重新輸入。
程式碼縮排解析差異
REPL 和 Python 指令碼在縮排解析上存在差異。REPL 對縮排的要求更為嚴格,需要在傳回縮排層級 0 時輸入空行,而 Python 指令碼則將空行視為上一層縮排的隱式繼續。
>>> num = 15
>>> if num % 3 == 0:
... print('Fizz')
... if num % 5 == 0:
File "<stdin>", line 3
if num % 5 == 0:
^
SyntaxError: invalid syntax
清單 1-2 在指令碼中可以正常執行,但在 REPL 中會出現錯誤:
for num in range(1, 101):
val = ''
if num % 3 == 0:
val += 'Fizz'
if num % 5 == 0:
val += 'Buzz'
if not val:
val = str(num)
print(val)
REPL 的最佳實踐
對於簡單的函式測試和理解函式工作原理,REPL 是非常有用的工具。然而,對於涉及複雜流程控制的任務,建議使用指令碼檔案進行開發,以避免 REPL 的侷限性。
Python除錯技術與工具應用
在軟體開發過程中,除錯(Debugging)是一個不可或缺的環節。Python作為一種廣泛使用的程式語言,提供了多種除錯工具和技術。本文將探討Python中常用的除錯方法,包括使用REPL(Read-Eval-Print Loop)、編寫Python指令碼以及利用內建的pdb除錯器。
使用REPL進行快速原型設計
REPL是Python的一種互動式環境,允許開發者快速測試程式碼片段。然而,在使用REPL時,容易出現縮排錯誤,如下所示:
>>> print(val)
File "<stdin>", line 1
print(val)
^
IndentationError: unexpected indent
這種錯誤在使用多行結構(如迴圈或條件陳述式)時尤其常見。雖然可以使用方向鍵回溯之前輸入的行,但多行結構無法被視為一個整體,導致重新執行迴圈體變得困難。
使用Python指令碼進行原型設計
與REPL相比,編寫Python指令碼可以更好地儲存和管理程式碼。開發者可以輕鬆地重新執行指令碼,並且程式碼儲存在檔案中,而不是終端機的捲動緩衝區中。然而,這種方法也存在一些缺點,例如無法在指令碼執行過程中與其互動,通常被稱為「printf除錯」。
在指令碼中新增print陳述式是一種常見的除錯手段,可以用來觀察變數的值或程式的執行流程。例如:
for num in range(1,101):
print(f"n: {num} n%3: {num%3} n%5: {num%5}")
內容解密:
for num in range(1,101)::這行程式碼使用for迴圈遍歷1到100的數字。print(f"n: {num} n%3: {num%3} n%5: {num%5}"):這行程式碼使用f-string格式化輸出當前數字num、以及num除以3和5的餘數。
這種方法雖然簡單易用,但也存在一些問題,例如需要重複編輯和執行指令碼,且輸出結果可能不容易閱讀。
結合指令碼與pdb進行除錯
pdb是Python內建的除錯器,是開發者的得力工具。它允許開發者逐步執行程式碼,檢查變數的值,並在複雜的表示式(如列表推導式)中除錯。
在pdb會話中,可以使用多個命令來控制除錯流程,包括:
step和next:執行當前陳述式並移動到下一條陳述式。step會進入函式內部,而next則不會。break和continue:設定斷點和繼續執行程式碼。debug:允許開發者指定任意的Python表示式進行除錯。
例如,使用step進入函式內部檢查其執行過程,或使用break設定斷點以檢查特定條件下的變數狀態。
使用pdb進行偵錯
在軟體開發過程中,除錯是不可或缺的一環。Python內建的pdb模組提供了一個強大的偵錯工具,可以幫助開發者逐步執行程式碼、檢查變數狀態,並診斷問題所在。
進入pdb偵錯模式
有兩種常見的方式可以進入pdb偵錯模式:
- 在程式碼中明確呼叫
pdb:可以在程式碼中插入import pdb; pdb.set_trace()或使用breakpoint()函式來啟動pdb偵錯模式。 - 事後偵錯(Post-mortem debugging):使用
python -m pdb yourscript.py命令執行指令碼,當發生異常時,pdb會自動啟動,讓你可以檢查當時的變數狀態。
pdb基本操作
進入pdb偵錯模式後,你可以使用以下命令來控制程式的執行:
continue:繼續執行程式,直到遇到下一個斷點或程式結束。step:逐步執行程式碼,可以進入函式內部。break:設定斷點,例如break 2, num==15會在第2行設定一個條件斷點,當num等於15時觸發。
> python -m pdb fizzbuzz.py
> c:\fizzbuzz_pdb.py(1)<module>()
-> def fizzbuzz(num):
(Pdb) break 2, num==15
Breakpoint 1 at c:\fizzbuzz.py:2
(Pdb) continue
內容解密:
- 使用
python -m pdb yourscript.py命令可以啟動事後偵錯模式。 (Pdb)是pdb的提示符號,表示目前處於偵錯模式。break 2, num==15在第2行設定了一個條件斷點,當num等於15時會觸發。
使用breakpoint()函式
Python 3.7之後,可以使用內建的breakpoint()函式來啟動pdb。這使得在程式碼中設定斷點變得更加方便。
for num in range(1, 101):
val = ''
if num == 15:
breakpoint()
if num % 3 == 0:
val += 'Fizz'
if num % 5 == 0:
val += 'Buzz'
if not val:
val = str(num)
print(val)
內容解密:
breakpoint()函式會在執行到該行時暫停程式,並進入pdb偵錯模式。- 這種方式比舊式的
import pdb; pdb.set_trace()更簡潔,也更容易閱讀。
使用Jupyter進行原型開發
Jupyter Notebook是一個強大的工具,允許你將程式碼分成多個區塊並獨立執行,非常適合用於原型開發和測試。
內容解密:
- Jupyter支援多種程式語言,包括Python、Julia和R。
- 它提供了一個互動式的環境,可以方便地展示和測試程式碼。