iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 17
0
Software Development

從零開始學Python系列 第 17

[Day 17] 從零開始學Python - 檔案讀寫:妳出現在我詩的每一頁(下)

  • 分享至 

  • xImage
  •  

註:本文同步刊載在Medium,若習慣Medium的話亦可去那邊看呦!

上一回我們介紹了CSV的格式以及使用方法,
事實上很多檔案如果是以Excel能表達的狀態下,
CSV應該可以應付絕大多數的需求了!
但對於許多程式開發,或較為複雜的資料,
使用CSV就會稍嫌力有未逮,
因為CSV並不能夠簡單分出比較大量的層級。

舉例來說,如果我們現在有一組資料,
內含了一個學校的兩個班級,
那可能會長這樣:

how_school = {
  "校長": "How哥",
  "工友": "林阿嘉",
  "class": {
    "A": {
      "teacher": "蔡阿嘎",
      "students": {
        "阿明": {"數學":55, "英文":70, "物理":55},
        "HowHow": {"數學":80, "英文":60, "物理":40}
      }
    },
    "B": {
      "teacher": "二伯",
      "students": {
        "小美": {"數學":90, "英文":88, "物理":100},
        "蔡哥": {"數學":50, "英文":50, "物理":40}
      }
    }
  }
}

像這樣子的東西,就很難使用csv簡單表現出來了!
所以我們一般會使用JSON來處理這樣子的結構。
JSON是JavaScript Object Notation的縮寫,
顧名思義,本來是用在JavaScript的格式。

後來大家發現實在是很好用,所以也被拿來在很多地方做為資料交換用的格式。
當然,如果要人從頭刻出來,可能中間會有一些沒寫好的地方容易出錯,
這時候我們需要一個用來檢查格式的工具,
讀者可以搜尋'JSON online editor',選擇自己用得順手的來嘗試編寫,
以下我們就拿在 https://jsoneditoronline.org/ 上操作做為範例:
進入時,幾個簡單的操作就看中間的部分:
https://ithelp.ithome.com.tw/upload/images/20200929/20119871oQnkazdUxL.jpg
左邊預設是code(原始的json碼),右邊預設是tree(JSON Object長的樣子);
我們可以寫好左邊以後,按一下"Copy>"將其複製到右邊產生tree
如果失敗的話,這個編輯器就會給你有關哪一行出錯的提示。
(反過來先產生tree再讓它翻成code也可以呦!)

預設裡應該會給出一段json碼如下,這是用來提示基本關於JSON的用法。

  "array": [
    1,
    2,
    3
  ],
  "boolean": true,
  "color": "gold",
  "null": null,
  "number": 123,
  "object": {
    "a": "b",
    "c": "d"
  },

首先留意到,每個單位一般都會以一個字串做為它的名字,
和Python不同,字串請全數用雙引號("")來括住,單引號在這裡是行不通的!
JSON常用的格式有以下幾個:
array(陣列):跟Python的串列基本相似,除了前面有一個它的名字(可自行命名),
後面使用中括號框住,以","逗號分隔。
boolean(布林值):可以放在值的地方,使用true/false(注意是全小寫!)。
color(色彩):使用文字來表示一些色彩的話,有些編輯器可以幫你解讀出來XD。
null(空):相當於Python的None,表示沒有東西存在。
number(數字):在JSON中數字可以是整數或小數。
object(物件):使用大括號框起,裡面的每一段跟字典相似,使用key:value的型態放入,
可以多層(但是key必須要是字串)。

那麼,一段Python中的資料結構,要怎麼轉換成JSON呢?
我們可以import json,並使用dumps()方法來處理:
(如果是從檔案的話要用dump()方法)

import json
how_json = json.dumps(how_school)
print(how_json)

結果如下......咦?這什麼鬼東西?!

C:\Users\Desolve>python fromzero.py
{"\u6821\u9577": "How\u54e5", "\u5de5\u53cb": "\u6797\u963f\u5609", "class": {"A": {"teacher": "\u8521\u963f\u560e", "students": {"\u963f\u660e": {"\u6578\u5b78": 55, "\u82f1\u6587": 70, "\u7269\u7406
": 55}, "HowHow": {"\u6578\u5b78": 80, "\u82f1\u6587": 60, "\u7269\u7406": 40}}}, "B": {"teacher": "\u4e8c\u4f2f", "students": {"\u5c0f\u7f8e": {"\u6578\u5b78": 90, "\u82f1\u6587": 88, "\u7269\u7406":
 100}, "\u8521\u54e5": {"\u6578\u5b78": 50, "\u82f1\u6587": 50, "\u7269\u7406": 40}}}}}

Python提供的json模組在進行dump/dumps方法時,
預設所有輸進來的內容全都是ASCII Code,
所以當超出這個範圍,例如我們輸入的中文,實質上應該要用UTF-8來表達才對。
所以我們改一下它的參數即可:

import json
how_json = json.dumps(how_school, ensure_ascii=False) # 我沒有要全ASCII,給我改回來XD
print(how_json)

執行結果如下:

C:\Users\Desolve>python fromzero.py
{"校長": "How哥", "工友": "林阿嘉", "class": {"A": {"teacher": "蔡阿嘎", "students": {"阿明": {"數學": 55, "英文": 70, "物理": 55}, "HowHow": {"數學": 80, "英文": 60, "物理": 40}}}, "B": {"teacher": "
二伯", "students": {"小美": {"數學": 90, "英文": 88, "物理": 100}, "蔡哥": {"數學": 50, "英文": 50, "物理": 40}}}}}

剛剛是將一個Python的資料結構轉成JSON字串,
那我們想要從JSON字串轉回Python的結構的話,
可以使用loads方法:

>>> how2 = json.loads(how_json) # 接續前面的how_json
>>> how2
{'校長': 'How哥', '工友': '林阿嘉', 'class': {'A': {'teacher': '蔡阿嘎', 'students': {'阿明': {'數學': 55, '英文': 70, '物理': 55}, 'HowHow': {'數學': 80, '英文': 60, '物理': 40}}}, 'B': {'teacher': '
二伯', 'students': {'小美': {'數學': 90, '英文': 88, '物理': 100}, '蔡哥': {'數學': 50, '英文': 50, '物理': 40}}}}}
>>> how2['校長']
'How哥'
>>> how2['工友']
'林阿嘉'
>>> how2['class']['A']
{'teacher': '蔡阿嘎', 'students': {'阿明': {'數學': 55, '英文': 70, '物理': 55}, 'HowHow': {'數學': 80, '英文': 60, '物理': 40}}}
>>>

我們可以從上面的範例看到,
在使用json時,轉換出來的Python結構,
基本上可以當成是字典,裡面有可能含有串列的部分,
操作起來不會有任何額外的問題,所以這點才對於Python相當重要,
因為直接讀進來一個檔案,就可以做為字典使用是非常方便的一件事情!

同樣我們再來嘗試一下寫到檔案和讀出來:

# 寫入到json,使用json.dump()
>>> classA = how2['class']['A']
>>> with open('classA.json', 'w') as f:
...     json.dump(classA, f)
...
>>> classA = how2['class']['A']
>>> with open('classA.json', 'w') as f:
...     json.dump(classA, f, ensure_ascii=False)
...
# 從json讀出,使用json.load()
>>> with open('classA.json', 'r') as f:
...     reclassA = json.load(f)
...
>>> reclassA
{'teacher': '蔡阿嘎', 'students': {'阿明': {'數學': 55, '英文': 70, '物理': 55}, 'HowHow': {'數學': 80, '英文': 60, '物理': 40}}}

最後,提醒讀者留意一件事情:
json當中的每個object必須要是獨一無二的,也就是不可以重名!
其實這點對照一下Python的字典應該就清楚了,
因為Python的字典的key也必須要是獨特的。
那,如果重名會怎樣呢?
一般狀況下,最後面出現的會蓋掉前面的:

>>> repeated_json = '{"數學": 80, "數學": 50, "數學": 30}'
>>> json.loads(repeated_json) # 越考越爛阿QQ
{'數學': 30}

當然,json還有不少其他的應用,
有興趣的讀者可以再閱讀相關文件學習:
https://docs.python.org/3/library/json.html?highlight=json#command-line-options

那麼,我們來做個練習:

  1. 政府資料開放平臺上有提供不少的免費取用的資料,
    請將 https://data.gov.tw/dataset/6224 的JSON格式檔案下載下來。
  2. 請用上面示範的方式將其打開並存成一個Python的資料結構,命名為bs,
    這中間可能會遇到讀取的問題,是JSON檔文字編碼的錯誤,
    請在打開檔案時額外給入 encoding="utf-8" 的參數。
  3. bs是一個什麼?(字串?串列?字典?)
  4. 請利用前面所學,將所有位在'臺北市'的書店資訊存成一個串列,名為taipei。
  5. taipei中特色書店點閱數超過2000的店家是哪幾家呢?請列出其名字。

那我們就明天見囉!


上一篇
[Day 16] 從零開始學Python - 檔案讀寫:妳出現在我詩的每一頁(中)
下一篇
[Day 18] 從零開始學Python - 系統模組:走路的不是強尼,是你心中的OS
系列文
從零開始學Python30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言