原創(chuàng):XIAO油菜花
學(xué)習(xí)進(jìn)度記錄:
《零基礎(chǔ)入門學(xué)習(xí)Python》P26:字典:當(dāng)索引不好用時(shí)2
《Python開發(fā)入門與爬蟲項(xiàng)目實(shí)戰(zhàn)》:Python中的函數(shù):遞歸查找
課后思考
0.Python的字典是否支持一鍵(Key)多值(Value)?
1.在字典中,如果試圖為一個(gè)不存在的鍵(Key)賦值會(huì)怎樣?
2.成員資格操作符(in和not in)可以檢查一個(gè)元素是否存在序列中,當(dāng)然也可以用來檢查一個(gè)鍵(Key)是否存在字典中,那么請(qǐng)問哪種的檢查效率更高些?為什么?
3.Python對(duì)鍵(Key)和值(Value)有沒有類型限制?
4.請(qǐng)目測(cè)下邊代碼執(zhí)行后,字典dict1的內(nèi)容是什么?
>>> dict1.fromkeys((1, 2, 3), ('one', 'two', 'three'))
>>> dict1.fromkeys((1, 3), '數(shù)字')
5.如果你需要將字典dict1 = {1: 'one', 2: 'two', 3: 'three'}拷貝到dict2,你應(yīng)該怎么做?
答案
0.不支持,對(duì)相同的鍵再次賦值會(huì)將上一次的值直接覆蓋。
1.會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)的鍵(Key)并添加相應(yīng)的值(Value)進(jìn)去。
2.在字典中檢查鍵(Key)更高效。因?yàn)樽值涞脑硎鞘褂霉K惴ù鎯?chǔ),一步到位,不需要使用查找算法進(jìn)行匹配,因此時(shí)間復(fù)雜度是O(1),效率非常高。
3.有。Python對(duì)鍵的要求相對(duì)要嚴(yán)格一些,要求它們必須是可哈希(Hash)的對(duì)象,不能是可變類型(包括變量、列表、字典本身等)。但是Python對(duì)值是沒有任何限制的,它們可以是任意的Python對(duì)象。
4.執(zhí)行完成后,字典dict1的內(nèi)容是:{1: '數(shù)字', 3: '數(shù)字'}
這里要注意的是,fromkeys方法是直接創(chuàng)建一個(gè)新的字典,不要試圖使用它來修改一個(gè)原有的字典,因?yàn)樗鼤?huì)直接無情的用把整個(gè)字典給覆蓋掉。
5.可以利用字典的copy()方法:dict2 = dict1.copy()。
實(shí)戰(zhàn)
0.嘗試編寫一個(gè)用戶登錄程序(這次嘗試將功能封裝成函數(shù)),程序?qū)崿F(xiàn)如圖:

user_data = {}
def new_user():
prompt = '請(qǐng)輸入用戶名:'
while True:
name = input(prompt)
if name in user_data:
prompt = '此用戶名已經(jīng)被使用,請(qǐng)重新輸入:'
continue
else:
break
passwd = input('請(qǐng)輸入密碼:')
user_data[name] = passwd
print('注冊(cè)成功,趕緊試試登錄吧^_^')
def old_user():
prompt = '請(qǐng)輸入用戶名:'
while True:
name = input(prompt)
if name not in user_data:
prompt = '您輸入的用戶名不存在,請(qǐng)重新輸入:'
continue
else:
break
passwd = input('請(qǐng)輸入密碼:')
pwd = user_data.get(name)
if passwd == pwd:
print('歡迎進(jìn)入XXOO系統(tǒng),請(qǐng)點(diǎn)右上角的X結(jié)束程序!')
else:
print('密碼錯(cuò)誤!')
def showmenu():
prompt = '''
|--- 新建用戶:N/n ---|
|--- 登錄賬號(hào):E/e ---|
|--- 推出程序:Q/q ---|
|--- 請(qǐng)輸入指令代碼:'''
while True:
chosen = False
while not chosen:
choice = input(prompt)
if choice not in 'NnEeQq':
print('您輸入的指令代碼錯(cuò)誤,請(qǐng)重新輸入:')
else:
chosen = True
if choice == 'q' or choice == 'Q':
break
if choice == 'n' or choice == 'N':
new_user()
if choice == 'e' or choice == 'E':
old_user()
showmenu()
知識(shí)點(diǎn)備忘
Python 的字典有好多個(gè)名稱("映射"、"哈希"、"散列"或者"關(guān)系數(shù)組"),那你知道為什么字典會(huì)被稱為 Hash(翻譯為"哈希"或"散列")嗎?你知道為什么字典對(duì)于鍵(Key)的存儲(chǔ)數(shù)據(jù)要求比較嚴(yán)格,但對(duì)于對(duì)應(yīng)的值(Value)的存儲(chǔ)卻要求很寬松嗎?
首先我們來解釋一下什么是 Hash,來自維基百科:
散列函數(shù)(或散列算法,又稱哈希函數(shù),英語:Hash Function)是一種從任何一種數(shù)據(jù)中創(chuàng)建小的數(shù)字“指紋”的方法。散列函數(shù)把消息或數(shù)據(jù)壓縮成摘要,使得數(shù)據(jù)量變小,將數(shù)據(jù)的格式固定下來。該函數(shù)將數(shù)據(jù)打亂混合,重新創(chuàng)建一個(gè)叫做散列值的指紋。散列值通常用來代表一個(gè)短的隨機(jī)字母和數(shù)字組成的字符串。好的散列函數(shù)在輸入域中很少出現(xiàn)散列沖突。在散列表和數(shù)據(jù)處理中,不抑制沖突來區(qū)別數(shù)據(jù),會(huì)使得數(shù)據(jù)庫(kù)記錄更難找到。
散列函數(shù)是用于從數(shù)據(jù)中創(chuàng)建小的數(shù)字指紋的方法。
Python 調(diào)用內(nèi)部的散列函數(shù),將鍵(Key)作為參數(shù)進(jìn)行轉(zhuǎn)換,得到一個(gè)唯一的地址(這也就解釋了為什么給相同的鍵賦值會(huì)直接覆蓋的原因,因?yàn)橄嗤逆I轉(zhuǎn)換后的地址是一樣滴),然后將值(Value)存放到該地址中。
對(duì)于 Python 來說,鍵(Key)必須是可哈希的,換句話說就是要可以通過散列函數(shù)計(jì)算出唯一地址的。那如果拿一個(gè)變量當(dāng)鍵(Key)可以嗎?肯定不行。因?yàn)樽兞侩S時(shí)都可能改變,不符合可哈希原則!
同樣的,列表、字典、集合這些都是可變的,所以都不能做為鍵(Key)來使用。
那有朋友可能會(huì)問,那元祖呢?元祖總該是不變的吧?
其實(shí)不然,因?yàn)樵胬镞吙梢源娣帕斜磉@類可變因素,所以如果實(shí)在想拿元祖當(dāng)字典的鍵(Key),那必須對(duì)元祖做限制:元組中只包括像數(shù)字和字符串這樣的不可變?cè)貢r(shí),才可以作為字典中有效的鍵(Key)。
另外還需要注意的一點(diǎn)是,Python 的哈希算法對(duì)相同的值計(jì)算得到的結(jié)果是一樣的,也就是說 12315 和 12315.0 的值相同,他們被認(rèn)為是相同的鍵(Key)。
如果你關(guān)注了我,希望你監(jiān)督我,鼓勵(lì)我,與我一起學(xué)習(xí),一起成長(zhǎng)!?