Python 入門指南 5.0
單元 35 - 存檔與載入
存檔要儲存什麼呢?直覺告訴我們應該要儲存 Encrypt 物件 (object) ,不過可以簡單點,儲存密碼表就可以了
↓
code.txt
完整程式請參考「範例程式碼」的 encrypt.py 、 encrypt_view.py 及 encrypt_controller.py 。
要直接儲存整個 Encrypt 物件到檔案也不是不可以,只是這麼一來就牽涉到物件還要序列化 (serialization) ,反倒因為密碼表是字串 (string) ,因此可以字串的方式來存檔。
儲存物件要利用標準程式庫 (standard library) 中的 pickle 模組 (module) 。
這是個相對簡單的方式,也就是說, Encrypt 類別 (class) 的 code 屬性 (attribute) 為密碼表字串,然後把這個字串儲存到一個固定檔名的純文字檔裡,就完成存檔的工作了。載入就讀取這個純文字檔,取得密碼表字串再重新建立 e ,並以密碼表字串當 __init__() 方法 (method) 的參數即可。
概念很簡單,可是跑程式時可能也會發生某些問題,例如 e 的初值為 None 的情況,如果使用者沒有按過新建就按下儲存,程式就會發生錯誤,因此這邊也要先進行條件 (condition) 檢查。
save_method() 方法的實作如下
57 59 61 62 64 66 68 | def save_method(self):
if self.e == None:
self.app.display_text["text"] = "無法儲存!"
else:
with open('./code.txt', 'w') as f:
f.write(str(self.e)[6:])
self.app.display_text["text"] = "完成存檔!"
|
這裡利用關鍵字 (keyword) with 、 as 與內建函數 (function) open() 打開並且建立檔案物件 f ,需要兩個參數 (parameter) ,第一個參數為檔案路徑名稱,第二個參數則是檔案處理模式,這裡 'w' 表示寫入,若 code.txt 不存在就會建立檔案
64 | with open('./code.txt', 'w') as f:
|
f 取得檔案物件,接著寫入內容到檔案是利用檔案物件的 write() 方法,參數就是要寫入的字串內容
66 | f.write(str(self.e)[6:])
|
注意上面 self.e 是 Encrypt 型態 (type) 的屬性,雖然重構 (refactoring) 後的 Encrypt 物件有 __str__() 方法可以直接回傳物件的字串形式,但是這裡涉及用序列 (sequence) 的索引值 (index) 取得子字串,因此 self.e[6:] 會被直譯器 (interpreter) 解讀是要用 Encrypt 類別使用索引值的方式,由於 Encrypt 類別並沒有設定用索引值的方式,因此會造成錯誤,所以要用內建函數 str() 先把 self.e 轉換成字串。
存檔工作結束後在訊息欄顯示檔案儲存成功訊息
68 | self.app.display_text["text"] = "完成存檔!"
|
載入則是讀取 code.txt 中的內容,因為檔案內容就是密碼表。不過載入時有可能發生檔案不存在的情況,就是使用者沒有按過儲存按鈕囉!這樣的話,相同目錄下不會存在 code.txt 檔案,所以這邊也是先做個檔案是否存在的條件檢查,程式如下
41 43 45 47 49 51 52 54 | def load_method(self):
if os.path.exists("./code.txt"):
with open('./code.txt', 'r') as f:
code = f.readline()
self.e = Encrypt(code)
self.app.display_text["text"] = self.e
else:
self.app.display_text["text"] = "無法載入!"
|
這裡我們先用 os.path.exists() 判斷檔案是否存在
43 | if os.path.exists("./code.txt"):
|
因為用了標準程式庫裡的 os 模組,所以前面要先 import os
8 | import os
|
若不存在訊息欄就顯示載入失敗的訊息,若存在就進行載入工作,這裡是用檔案物件的 readline() 方法
47 | code = f.readline()
|
然後我們將 code 設定給 e 即可,這裡同樣 e 直接建立一個帶有參數的 Encrypt 物件
49 | self.e = Encrypt(code)
|
來執行看看囉!下面是存檔
相同目錄下就會新增 code.txt
開啟 code.txt 檢查密碼表是否有存入
下面是載入
功能 OK ,接下來就剩兩個方法要完成實作囉!
中英文術語對照 | |
---|---|
屬性 | attribute |
類別 | class |
條件 | condition |
函數 | function |
索引值 | index |
直譯器 | interpreter |
關鍵字 | keyword |
方法 | method |
模組 | module |
物件 | object |
參數 | parameter |
重構 | refactoring |
序列 | sequence |
序列化 | serialization |
標準程式庫 | standard library |
字串 | string |
型態 | type |
重點整理 |
---|
1. 存檔可儲存物件或字串,儲存物件須使用標準程式庫中的 pickle ,儲存字串可將字串直接寫入純文字檔案中。 |
2. 檔案處理利用關鍵字 with 、 as 及內建函數 open() ,取得檔案物件後利用 write() 方法寫入資料,而 readline() 可讀取資料,由於是用關鍵字 with ,因此結束檔案處理工作後會自動調用 closed 關閉檔案物件。 |
3. os.path.exists() 可判斷指定路徑的檔案是否存在。 |
4. GUI 中任何一個動作都應該要顯示提示訊息給使用者,好讓使用者知道操作是否成功。 |
問題與討論 |
---|
1. 為什麼儲存物件還要序列化,字串也是物件,可是字串卻不用? |
2. 載入前如果檔案不存在會發生什麼情況?有其他的解決方式嗎? |
練習 |
---|
1. 寫一個程式 exercise3501.py ,利用 Entry 、 Button 、 Label 設計一個猜數字遊戲的 GUI 。 參考程式碼 |
2. 承上題,將新程式寫在 exercise3502.py 中,利用單元 27 練習 5 的 Guess 類別,建立猜數字遊戲的遊戲流程。 參考程式碼 |
3. 承上題,將新程式寫在 exercise3503.py 中,加入一個 重新 按鈕,讓遊戲結束後可以再次重複進行。 參考程式碼 |
4. 承上題,將新程式寫在 exercise3504.py 中,改成全按鈕輸入的 GUI ,可加入一個 清空 輸入的按鈕。 參考程式碼 |
5. 承上題,將新程式寫在 exercise3505.py 中,利用按鈕的 config() 方法,將 state 設定為,這可以用來鎖住 0 與 再一次 按鈕。 參考程式碼 |
6. 承上題,將新程式寫在 exercise3506.py 中,實作 清空 按鈕對應的程式碼。 參考程式碼 |
7. 承上題,將新程式寫在 exercise3507.py 中,實作數字按鈕對應的程式碼,按下數字按鈕後要鎖住該數字按鈕,並且顯示按下的數字到輸出欄,注意 清空 按鈕部分需要有相對應解鎖的程式碼。 參考程式碼 |
8. 承上題,將新程式寫在 exercise3508.py 中,加入 run_game() 方法,在使用者按下猜測數字數量之後進行遊戲結算。 參考程式碼 |
9. 承上題,將新程式寫在 exercise3509.py 中,實作 再一次 按鈕對應的程式碼。 參考程式碼 |
10. 承上題,將新程式寫在 exercise3510.py 中,增加在每一次猜中遊戲結束顯示平均猜測次數。 參考程式碼 |