Python Tutorial 第二堂(3)函式、模組、類別與套件
Python Tutorial 第二堂(2)容器、流程、for 包含式 << 前情 此文件已有新版,詳見〈Python 3 Tutorial 第三堂(1)函式、模組、類別與套件〉。 在 Python 中,每個東西都是物件,那麼 Python 是以物件導向作為主要典範嗎?不,Python 之父 Guido van Rossum 曾在《Masterminds of Programming》書中談到: Python supports procedural programming, to some extent, and OO. These two aren’t so different, and Python’s procedural style is still strongly influenced by objects (since the fundamental data types are all objects). Python supports a tiny bit of functional programming—but it doesn’t resemble any real functional language, and it never will. 基本上,無論採用何種典範,關鍵在於架構程式時應思考的幾個重點,像是…
只有在腦海中清楚地思考過這幾個重點,才能在程式語言中採用適當的機制來加以實現,或者是在程式語言不支援時,想辦法自行實作類似機制,像是在 JavaScript 中,即使沒有名稱空間及套件機制,仍有開發者依各自需求實現各種風格的機制,來解決對應的問題。 幸運地,Python 中對於這幾個思考重點,在實作時提供的機制頗為完整,提供了像是函式(Function)、模組(Module)、類別(Class)與套件等支援。 函式當發現到兩個程式片段極為類似,只有當中幾個計算用到的數值或變數不同時,例如: ... max1 = a if a > b else b ... max2 = x if x > y else y ... 可以使用函式來封裝程式片段,將流程中引用不同數值或變數的部份設計為參數,例如: def max(a, b): return a if a > b else b 函式是一種抽象,對流程的抽象,在定義了 在上面的 Python 程式碼中定義了一個函式,在 Python 中,函式不單只是定義,也是個值,舉例而言,你可以如下將 maximum = max maximum(10, 20) # 傳回 20 在 Python 中,可以使用 lambda a, b: a if a < b else b 這樣的函式稱為 λ 函式或是匿名函式(Anonymous function),當然,你可以將函式指定給變數: min = lambda a, b: a if a < b else b minimum = min min(10, 20) # 傳回10 minimum(10, 20) # 傳回10 模組如果你有一大堆數學相關的函式與常數定義,像是: def max(a, b): return a if a > b else b def min(a, b): return a if a < b else b def sum(*numbers): # numbers 接受可變長度引數 total = 0 for number in numbers: total += number return total pi = 3.141592653589793 e = 2.718281828459045 該怎麼組織它們,讓它們有別於其他開發者撰寫的函式與常數定義?避免名稱空間衝突問題?像是其他開發者也在其他地方定義了自己的 在 Python 中,模組是幾個重要抽象層的機制之一,也許是最自然的機制之一,只要你建立了一個原始碼檔案 modu.py,你就建立了一個模組
模組提供了名稱空間。模組中的變數、函式與類別,基本上需透過模組的名稱空間來取得。在 Python 中, import xmath print '# import xmath' print xmath.pi print xmath.max(10, 5) print xmath.sum(1, 2, 3, 4, 5) print '# import xmath as math' import xmath as math # 為 xmath 模組取別名為 math print math.e print '# from xmath import min' from xmath import min # 將 min 複製至目前模組,不建議 from modu import *,易造成名稱衝突 print min(10, 5) 結果應該會顯示: 類別對於熟悉物件導向的開發者而言,可能會問:「那類別的應用場合呢?」…嗯…當打算將某些狀態與功能黏在一起時…例如你可能原本有這樣的一個 bank.py: def account(name, number, balance): return {'name': name, 'number': number, 'balance': balance} def deposit(acct, amount): if amount <= 0: raise ValueError('amount must be positive') acct['balance'] += amount def withdraw(acct, amount): if amount > acct['balance']: raise RuntimeError('balance not enough') acct['balance'] -= amount def to_str(acct): return 'Account:' + str(acct) 當中是有關於帳戶建立、存款、提款等函式,你會這麼使用: import bank acct = bank.account('Justin', '123-4567', 1000) bank.deposit(acct, 500) bank.withdraw(acct, 200) print bank.to_str(acct) 實際上, class Account: def __init__(self, name, number, balance): self.name = name self.number = number self.balance = balance def deposit(self, amount): if amount <= 0: raise ValueError('amount must be positive') self.balance += amount def withdraw(self, amount): if amount > self.balance: raise RuntimeError('balance not enough') self.balance -= amount def __str__(self): return 'Account({0}, {1}, {2})'.format( self.name, self.number, self.balance) 在 在類別中還定義了 如此定義之後,客戶端在使用上就容易得多了… import bank acct = bank.Account('Justin', '123-4567', 1000) acct.deposit(500) acct.withdraw(200) print acct 是的!容易使用!在討論物件導向時,大家總是愛談可重用性(Reusability),然而要談到重用性的話,函式的重用性還高上許多,在考量物件導向時,易用性(Usability)其實才是它的重點。 套件假設現在你有一些 .py 檔案,別人同樣也有一堆 .py 檔案,你們的檔案現在得放在同一專案中,那麼檔案名稱衝突是有可能發生的,最好是為你們的 .py 檔案分別開設目錄。使用 Python 時,你可以在開設的目錄中放個 __init__.py 檔案,這樣 Python 就會將這個目錄視為一個套件,而目錄名稱就是套件名稱。 使用 練習 5:運用模組、類別與套件來組織程式 在練習用的檔案中,有個 exercises/exercise5/main.py,裏頭草草寫了一堆函式與變數,以及執行結果輸出的程式碼,請利用這邊介紹的模組、類別與套件,來重新組織當中可重用的程式碼,讓它們可以位於 最後,你完成的程式在實體架構上,應該會像是以下的圖片示意(如果不知道怎麼完成實作,記得參考練習用檔案中 solutions/exercise5 的成果 ): 完成這個練習後,第二堂應該時間就差不多到了,休息一下,接下來的第三堂課要來認識 Python 的社群、文件以及更多的 API … 參考資源
* http://docs.python.org/2/reference/datamodel.html#object.__repr__
* http://openhome.cc/Gossip/Python/ListType.html
* http://openhome.cc/Gossip/Python/ModuleABC.html
http://maxburstein.com/blog/python-shortcuts-for-the-python-beginner/ |