Python 入門指南 5.0
單元 22 - Encrypt 類別
類別 (class) 為 Python 開發軟體 (software) 的要角,因為類別用來設計物件 (object) ,軟體的實際運作則是藉由物件與物件的互動。我們接下來進入實際開發軟體的階段,到 GUI 篇會發展出一個 GUI 軟體,而在「Brython 篇」會把發展出的 Encrypt 類別應用在網頁 App 中
⇘
EncryptController
我們打算發展的一個替英文句子編密碼的軟體,主要功能是做小寫字母的替換,例如 "There is no spoon." 可能變成以下任一個
Tfqdq ki jo itooj.
Tcnan hf gl fqllg.
Tczmz dn ij nkjji.
Tgfsf pb ir barri.
Tdcpc my fo yxoof.
|
首先,我們要發展 Encrypt 類別,主要功能是建立一個英文小寫字母的對換表格,藉由這個表格,我們可以將英文句子中的小寫英文字母進行對換,然後開發圖形使用者介面 (graphical user interface) 的 EncryptGUI 類別。
GUI 的外觀如下圖
我們的 GUI 設計採用標準程式庫 (standard library) 的 Tk ,主要原因是 Tk 直建內建在 Python 官方直譯器 (interpreter) 中,無須額外整合第三方程式庫 (third party library) 。
有兩個可供輸入的文字欄位 (text field) ,其中一個我們作為輸出的顯示訊息之用,另有三個標籤 (label) ,顯示文字的提示訊息,七個按鈕 (button) ,提供 新建 、 開啟 、 儲存 Encrypt 物件,與 編碼 、 解碼 所輸入的英文句子, 清除 所有輸入欄位,以及 拷貝 輸出結果等的功能。
最後在 Brython 篇,把原本在 GUI 的功能移植到網頁上,利用瀏覽器 (browser) 進行編碼及解碼的功能
Brython 為第三方程式庫,立意是直接在瀏覽器中執行 Python 程式,用以取代 JavaScript 。
現在我們先來看看所有功能的核心,也就是 Encrypt 類別,我們的目的是,建立一個小寫英文字母的轉換表格,然後編碼、解碼都可直接依據這個表格。我們打算用下面的數學公式建立表格
y = a * x + b
m = y % n
r = m + diff
|
這裡的概念是利用字元的 Unicode 編碼順序,假設 x 為字元的原始編碼, Unicode 編碼中 'a' 為 97 ,然後將 x 乘上變數 (variable) a , 再加上變數 b ,假設兩者均是 0 到 9 的隨機整數,這樣便得到 y 的值。
然後將 y 除以 n 取得餘數 m , n 為所要轉換的字元數量,英文小寫字母共有 26 個,所以這裡 n 等於 26 ,因此 m 等於 0 到 25 之間的整數值。最後將 m 加上 diff , diff 也就是編碼系統的差值,由於 Unicode 中 'a' 為 97 ,所以這裡 diff 要以 97 代入。
因此,餘數 0 的字元會替換成 'a' ,餘數 1 的字元會被替換成 'b' ,餘數 2 的字元會被替換成 'c' ,餘下 23 個字元類推。這樣的計算需要進行 n 次,也就是 26 次,我們最後得到一組餘數與相對應字元的表格,這就是我們需要的表格了。
重複 n 次,我們需要一個迴圈 (loop) ,由於重複次數確定,因此 while 迴圈 (while loop) 就可以了,那我們要用什麼東西來儲存這個表格呢? Python 有很多內建的資料結構 (data structure) ,可以依資料特性有效率的處理資料,這裡,我們利用字串 (string) 就可以了。
字串就像是不可變的 (immutable) 串列 (list) ,這意思是說,字串可像串列用索引值存取裡頭的元素 (element) ,也就是長度為 1 的子字串,索引值恰巧是從 0 開始,這也完全符合我們計算餘數從 0 開始的需求。
我們先寫個開發規格的版本,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | # 定義 Encrypt 類別
class Encrypt:
# 定義建構子
def __init__(self):
# 建立密碼表
self.set_code()
# _code 的 getter
@property
def code(self):
return self.__code
# _code 的 setter
def set_code(self):
self.__code = "code"
# 編碼的方法
def toEncode(self, str):
pass
# 解碼的方法
def toDecode(self, str):
pass
# 測試部分
if __name__ == '__main__':
e = Encrypt()
print()
print(e.code)
print()
# 檔名: encrypt01.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
|
Encrypt 的 __init__() 就是呼叫 setcode()
4 6 | def __init__(self):
self.set_code()
|
密碼表預計儲存在封裝後的 __code 屬性 (attribute) ,這裡 setcode() 先簡單指派 "code" 字串給 __code
14 15 | def set_code(self):
self.__code = "code"
|
由於 __code 被封裝 (encapsulation) ,由於 __code 屬性在後續還是需要印出來查看是否正確,因此額外設定 code 屬性,回傳 __code
9 10 11 | # _code 的 getter
@property
def code(self):
return self.__code
|
這樣一來,底下測試部分就可以直接印出 code
26 27 28 29 30 | if __name__ == '__main__':
e = Encrypt()
print()
print(e.code)
print()
|
負責編碼與解碼的 toEncode() 與 toDecode() 方法則是先寫出來,關鍵字 (keyword) pass 表示什麼事都不做的陳述 (statement)
18 19 22 23 | def toEncode(self, str):
pass
def toDecode(self, str):
pass
|
encrypt01.py 為 Encrypt 類別基本的規格,接下來我們把公式放進 setcode() ,來建立實際的密碼表囉!
中英文術語對照 | |
---|---|
屬性 | attribute |
瀏覽器 | browser |
按鈕 | button |
類別 | class |
資料結構 | data structure |
元素 | element |
封裝 | encapsulation |
圖形使用者介面 | graphical user interface |
不可變的 | immutable |
直譯器 | interpreter |
關鍵字 | keyword |
標籤 | label |
串列 | list |
迴圈 | loop |
物件 | object |
標準程式庫 | standard library |
陳述 | statement |
字串 | string |
軟體 | software |
文字欄位 | text field |
第三方程式庫 | third party library |
while 迴圈 | while loop |
變數 | variable |
重點整理 |
---|
1. Encrypt 類別的主類功能是轉換句子中的英文小寫字母,最後作為 GUI 軟體的核心部分。 |
2. Encrypt 類別以數學公式建立英文字母的轉換表格,用字串當實體屬性儲存表格。 |
3. Python 中有許多內建的資料結構,字串像是不可變的串列,可用索引值存取長度為 1 的子字串。 |
4. Unicode 中, 'a' 的整數值為 97 。 |
5. 關鍵字 pass 是什麼事都不做的陳述。 |
6. 軟體規格是依據需求制定的功能表列。 |
問題與討論 |
---|
1. 為什麼 Encrypt 類別是要當作 GUI 軟體的核心?不能讓 Encrypt 類別直接成為大展神威的 GUI 軟體嗎? |
2. 除了數學公式外,有其他的方式可以建立轉換表格嗎? |
3. 為什麼程式的發展要逐步來?不能一次到位嗎? |
練習 |
---|
1. 寫一個程式 exercise2201.py ,定義繼承自 Exception 的 ParameterError ,在 __str__() 部分回傳 "參數型態錯誤" ,執行部分直接發起 ParameterError 例外。 參考程式碼 |
2. 承上題,將新程式寫在 exercise2202.py 中,定義比較參數大小的函數 higher() ,檢查參數是否為整數,如果參數不是整數就發起 ParameterError ,反之回傳比較結果。 參考程式碼 |
3. 承上題,將新程式寫在 exercise2203.py 中,在命令列接收使用者輸入,比較跟固定數字例如 100 的大小。。 參考程式碼 |
4. 承上題,將新程式寫在 exercise2204.py 中,利用標準程式庫中 random 的 randint() 取得 1 到 99 之間的整數,然後取得使用者輸入的數字,將隨機數字跟輸入數字比較大小。 參考程式碼 |
5. 承上題,將新程式寫在 exercise2205.py 中,改成比大小的遊戲。 參考程式碼 |
6. 承上題,將新程式寫在 exercise2206.py 中,改成猜數字遊戲。 參考程式碼 |
7. 承上題,將新程式寫在 exercise2207.py 中,加入 while True 迴圈,直到使用者猜對才結束遊戲。 參考程式碼 |
8. 承上題,將新程式寫在 exercise2208.py 中,加入 count 變數記錄猜測次數。 參考程式碼 |
9. 承上題,將新程式寫在 exercise2209.py 中,加入使用者猜測大或小的提示。 參考程式碼 |
10. 承上題,將新程式寫在 exercise2210.py 中,將猜數字遊戲定義放到函數 guess_game() 中。 參考程式碼 |