#! /usr/bin/env python
-*- coding:utf-8 -*-
'''
@Author:gcan
@Email:1528667112@qq.com
@Site:http://www.gcan.top
@File:json_data.py
@Software:PyCharm
@Date:2018-05-15 23:08:46
@Version:1.0.0
'''
存儲數(shù)據(jù)
很多程序都要求用戶輸入某種信息,如讓用戶存儲游戲首選項(xiàng)或提供要可視化的數(shù)據(jù)。不管專注的是什么,程序都把用戶提供的信息存儲在列表和字典等數(shù)據(jù)結(jié)構(gòu)中。用戶關(guān)閉
程序時,你幾乎總是要保存他們提供的信息;一種簡單的方式是使用模塊json 來存儲數(shù)據(jù)。
模塊json 讓你能夠?qū)⒑唵蔚腜ython數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)儲到文件中,并在程序再次運(yùn)行時加載該文件中的數(shù)據(jù)。你還可以使用json 在Python程序之間分享數(shù)據(jù)。更重要的是,JSON數(shù)據(jù)
格式并非Python專用的,這讓你能夠?qū)⒁訨SON格式存儲的數(shù)據(jù)與使用其他編程語言的人分享。這是一種輕便格式,很有用,也易于學(xué)習(xí)。 注意 JSON(JavaScript Object Notation)格式最初是為JavaScript開發(fā)的,但隨后成了一種常見格式,被包括Python在內(nèi)的眾多語言采用。
使用json.dump() 和json.load()
我們來編寫一個存儲一組數(shù)字的簡短程序,再編寫一個將這些數(shù)字讀取到內(nèi)存中的程序。第一個程序?qū)⑹褂胘son.dump() 來存儲這組數(shù)字,而第二個程序?qū)⑹?br>
用json.load() 。
函數(shù)json.dump() 接受兩個實(shí)參:要存儲的數(shù)據(jù)以及可用于存儲數(shù)據(jù)的文件對象。下面演示了如何使用json.dump() 來存儲數(shù)字列表:
import json
numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'
with open(filename, 'w') as f_obj:
json.dump(numbers, f_obj)
我們先導(dǎo)入模塊json ,再創(chuàng)建一個數(shù)字列表。我們指定了要將該數(shù)字列表存儲到其中的文件的名稱。通常使用文件擴(kuò)展名.json來指出文件存儲的數(shù)據(jù)為JSON格式。
接下來,我們以寫入模式打開這個文件,讓json 能夠?qū)?shù)據(jù)寫入其中。我們使用函數(shù)json.dump() 將數(shù)字列表存儲到文件numbers.json中。
這個程序沒有輸出,但我們可以打開文件numbers.json,看看其內(nèi)容。數(shù)據(jù)的存儲格式與Python中一樣: [2, 3, 5, 7, 11, 13]
下面再編寫一個程序,使用json.load() 將這個列表讀取到內(nèi)存中:
import json
filename = 'numbers.json'
with open(filename) as f_obj:
numbers = json.load(f_obj)
print(numbers)
我們確保讀取的是前面寫入的文件。這次我們以讀取方式打開這個文件,因?yàn)镻ython只需讀取這個文件。我們使用函數(shù)json.load() 加載存儲在 numbers.json中的信息,并將其存儲到變量numbers 中。
最后,我們打印恢復(fù)的數(shù)字列表,看看它是否與number_writer.py中創(chuàng)建的數(shù)字列表相同: [2, 3, 5, 7, 11, 13]
保存和讀取用戶生成的數(shù)據(jù)
對于用戶生成的數(shù)據(jù),使用json 保存它們大有裨益,因?yàn)槿绻灰阅撤N方式進(jìn)行存儲,等程序停止運(yùn)行時用戶的信息將丟失。
下面來看一個這樣的例子:用戶首次運(yùn)行程序時 被提示輸入自己的名字,這樣再次運(yùn)行程序時就記住他了。
我們先來存儲用戶的名字:
import json
username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username + "!")
我們提示輸入用戶名,并將其存儲在一個變量中。接下來,我們調(diào)用json.dump() ,并將用戶名和一個文件對象傳遞給它,從而將用戶名存儲到文件中。然后,我們打印一條消息,指出我們存儲了他輸入的信息
現(xiàn)在再編寫一個程序,向其名字被存儲的用戶發(fā)出問候:
import json
filename = 'username.json'
with open(filename) as f_obj:
username = json.load(f_obj)
print("Welcome back, " + username + "!")
我們使用json.load() 將存儲在username.json中的信息讀取到變量username 中?;謴?fù)用戶名后,我們就可以歡迎用戶回來了
我們需要將這兩個程序合并到一個程序(remember_me.py)中。這個程序運(yùn)行時,我們將嘗試從文件username.json中獲取用戶名,
因此我們首先編寫一個嘗試恢復(fù)用戶名的try 代 碼塊。如果這個文件不存在,我們就在except 代碼塊中提示用戶輸入用戶名,并將其存儲在username.json中,以便程序再次運(yùn)行時能夠獲取它
如果以前存儲了用戶名,就加載它
否則,就提示用戶輸入用戶名并存儲它
import json
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input("What is your name? ")
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username + "!")
else:
print("Welcome back, " + username + "!")
這里沒有任何新代碼,只是將前兩個示例的代碼合并到了一個程序中。我們嘗試打開文件username.json。如果這個文件存在,就將其中的用戶名讀取到內(nèi)存中,
再執(zhí)行else 代碼塊,即打印一條歡迎用戶回來的消息。用戶首次運(yùn)行這個程序時,文件username.json不存在,將引發(fā)FileNotFoundError 異常,因此Python將執(zhí) 行except 代碼塊:
提示用戶輸入其用戶名,再使用json.dump() 存儲該用戶名,并打印一句問候語。
無論執(zhí)行的是except 代碼塊還是else 代碼塊,都將顯示用戶名和合適的問候語。
重構(gòu)
你經(jīng)常會遇到這樣的情況:代碼能夠正確地運(yùn)行,但可做進(jìn)一步的改進(jìn)——將代碼劃分為一系列完成具體工作的函數(shù)。這樣的過程被稱為重構(gòu) 。重構(gòu)讓代碼更清晰、更易于理解、更容易擴(kuò)展。
要重構(gòu),可將其大部分邏輯放到一個或多個函數(shù)中。重點(diǎn)是問候用戶,因此我們將其所有代碼都放到一個名為greet_user() 的函數(shù)中:
import json
def greet_user():
"""問候用戶,并指出其名字"""
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input("What is your name? ")
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username + "!")
else:
print("Welcome back, " + username + "!")
greet_user()
考慮到現(xiàn)在使用了一個函數(shù),我們刪除了注釋,轉(zhuǎn)而使用一個文檔字符串來指出程序是做什么的。這個程序更清晰些,但函數(shù)greet_user() 所做的不僅僅是問候用戶,還在存儲了用戶名時獲取它,而在沒有存儲用戶名時提示用戶輸入一個。
下面來重構(gòu)greet_user() ,讓它不執(zhí)行這么多任務(wù)。為此,我們首先將獲取存儲的用戶名的代碼移到另一個函數(shù)中:
import json
def get_stored_username():
"""如果存儲了用戶名,就獲取它"""
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
return None
else:
return username
def greet_user():
"""問候用戶,并指出其名字"""
username = get_stored_username()
if username:
print("Welcome back, " + username + "!")
else:
username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username + "!")
greet_user()
新增的函數(shù)get_stored_username() 目標(biāo)明確,文檔字符串指出了這一點(diǎn)。如果存儲了用戶名,這個函數(shù)就獲取并返回它;
如果文件username.json不存在,這個函數(shù) 就返回None。這是一種不錯的做法:函數(shù)要么返回預(yù)期的值,要么返回None ;這讓我們能夠使用函數(shù)的返回值做簡單測試。
如果成功地獲取了用戶名,就打印一條歡迎用戶回來的消息,否則就提示用戶輸入用戶名。