1. 程式人生 > >第026講:字典:當索引不好用時2

第026講:字典:當索引不好用時2

目錄

測試題

0. Python的字典是否支援一鍵(Key)多值(Value)?

1. 在字典中,如果試圖為一個不存在的鍵(Key)賦值會怎樣?

2. 成員資格操作符(in和not in)可以檢查一個元素是否存在序列中,當然也可以用來檢查一個鍵(Key)是否存在字典中,那麼請問哪種的檢查效率更高些?為什麼?

3. Python對鍵(Key)和值(Value)有沒有型別限制?

4. 請目測下邊程式碼執行後,字典dict1的內容是什麼?

5. 如果你需要將字典dict1 = {1: 'one', 2: 'two', 3: 'three'}拷貝到dict2,你應該怎麼做?

動動手

0. 嘗試編寫一個使用者登入程式(這次嘗試將功能封裝成函式),程式實現如圖:

1. 請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!


測試題

0. Python的字典是否支援一鍵(Key)多值(Value)?

 

答:不支援,對相同的鍵再次賦值會將上一次的值直接覆蓋。

>>> dict1 = {1:'one', 1:'yi'}
>>> dict1[1]
'yi'

1. 在字典中,如果試圖為一個不存在的鍵(Key)賦值會怎樣?

答:會自動建立對應的鍵(Key)並新增相應的值(Value)進去。(具體原理可以參考第3題的“擴充套件閱讀”部分)

2. 成員資格操作符(in和not in)可以檢查一個元素是否存在序列中,當然也可以用來檢查一個鍵(Key)是否存在字典中,那麼請問哪種的檢查效率更高些?為什麼?

答:在字典中檢查鍵(Key)是否存在比在序列中檢查指定元素是否存在更高效。因為字典的原理是使用雜湊演算法儲存,一步到位,不需要使用查詢演算法進行匹配,因此時間複雜度是O(1),效率非常高。(關於如何使用雜湊演算法儲存的具體原理可以參考第3題的“擴充套件閱讀”部分)

3. Python對鍵(Key)和值(Value)有沒有型別限制?

答:Python對鍵的要求相對要嚴格一些,要求它們必須是可雜湊(Hash)的物件,不能是可變型別(包括變數、列表、字典本身等)。

但是Python對值是沒有任何限制的,它們可以是任意的Python物件。
如果不清楚雜湊原理以及字典的存放原理的童鞋,推薦閱讀下小甲魚幫你整理的這篇文章:你知道Python的字典(Dict)是如何儲存的嗎?(

http://bbs.fishc.com/thread-45016-1-1.html

4. 請目測下邊程式碼執行後,字典dict1的內容是什麼?

>>> dict1.fromkeys((1, 2, 3), ('one', 'two', 'three')) 
>>> dict1.fromkeys((1, 3), '數字')

答:執行完成後,字典dict1的內容是:{1: '數字', 3: '數字'}
這裡要注意的是,fromkeys方法是直接建立一個新的字典,不要試圖使用它來修改一個原有的字典,因為它會直接無情的用把整個字典給覆蓋掉。

5. 如果你需要將字典dict1 = {1: 'one', 2: 'two', 3: 'three'}拷貝到dict2,你應該怎麼做?

答:可以利用字典的copy()方法:dict2 = dict1.copy(),在其他語言轉移到Python小夥伴們剛開始可能會習慣性的直接用賦值的方法(dict2 = dict1),這樣子做在Python中只是將物件的引用拷貝過去而已。

看一下區別:

>>> a = {1:'one', 2:'two', 3:'three'}
>>> b = a.copy()
>>> c = a
>>> c[4] = 'four'
>>> c
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}

動動手

0. 嘗試編寫一個使用者登入程式(這次嘗試將功能封裝成函式),程式實現如圖:


user_data = {}

def new_user():
    prompt = '請輸入使用者名稱:'
    while True:
        name = input(prompt)
        if name in user_data:
            prompt = '此使用者名稱已經被使用,請重新輸入:'
            continue
        else:
            break

    passwd = input('請輸入密碼:')
    user_data[name] = passwd
    print('註冊成功,趕緊試試登入吧^_^')

def old_user():
    prompt = '請輸入使用者名稱:'
    while True:
        name = input(prompt)
        if name not in user_data:
            prompt = '您輸入的使用者名稱不存在,請重新輸入:'
            continue
        else:
            break
    
    passwd = input('請輸入密碼:')
    pwd = user_data.get(name)
    if passwd == pwd:
        print('歡迎進入XXOO系統,請點右上角的X結束程式!')
    else:
        print('密碼錯誤!')

def showmenu():
    prompt = '''
|--- 新建使用者:N/n ---|
|--- 登入賬號:E/e ---|
|--- 推出程式:Q/q ---|
|--- 請輸入指令程式碼:'''

    while True:
        chosen = False
        while not chosen:
            choice = input(prompt)
            if choice not in 'NnEeQq':
                print('您輸入的指令程式碼錯誤,請重新輸入:')
            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()

1. 請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!

比序列更加使用的對映型別,Python唯一的一個對映型別就是字典,字典也有一個關鍵符號,就是大括號,跟序列一樣,也可以用 dict() 這個工廠函式來建立一個字典,跟序列不一樣的是,如果在序列中試圖為一個不存在的位置去賦值的時候,會報錯,會提示該位置並不存在,但如果在字典中,它會自動建立相應的鍵並新增對應的值。

dict() 是一個工廠函式,實際上是一個型別,呼叫它會生成一個該型別的例項,此前我們學習了str(),int(),list(),tuple(),這些都是工廠函式(型別),不過在學習類和物件之前,你可以把它們當做普通函式來理解。

1、下面介紹字典的內建方法

fromkeys(....)

用法:dict.fromkeys(S[ ,v]) -> New dict with keys from S and values equal to v(v default to None).

你可以用fromkeys(....)方法建立並返回新的字典,第一個引數S是字典的鍵值,第二個引數v是可選的鍵值對應的值,如果第二個引數不提供的話,就是None。

>>> dict1 = {}
>>> dict1.fromkeys((1, 2, 3))
{1: None, 2: None, 3: None}
>>> dict1
{}

dict1.fromkeys()只是建立新的字典,對原陣列無影響,和下面的程式碼是一樣的:

dict.fromkeys((1, 2, 3))
{1: None, 2: None, 3: None}

如果給鍵對應的值的話:

>>> dict.fromkeys((1, 2, 3), 'number')
{1: 'number', 2: 'number', 3: 'number'}

但是不要指望分別給鍵對應的值:

>>> dict.fromkeys((1, 2, 3), ('one', 'two', 'three'))
{1: ('one', 'two', 'three'), 2: ('one', 'two', 'three'), 3: ('one', 'two', 'three')}

2、下面介紹訪問字典的幾個方法

keys()、values()、items()

keys()返回字典鍵的引用,values()返回字典值的引用,items()返回字典項的引用

>>> dict1 = {1:'one', 2:'two', 3:'three', 4:'four', 5:'five'}
>>> dict1.keys()
dict_keys([1, 2, 3, 4, 5])
>>> dict1.values()
dict_values(['one', 'two', 'three', 'four', 'five'])
>>> dict1.items()
dict_items([(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five')])

>>> for eachkey in dict1.keys():
    print(eachkey, end = ' ')

    
1 2 3 4 5 

>>> for eachvalue in dict1.values():
    print(eachvalue, end = ' ')

    
one two three four five 

>>> for eachitem in dict1.items():
    print(eachitem, end = ' ')

    
(1, 'one') (2, 'two') (3, 'three') (4, 'four') (5, 'five') 

當我們試圖訪問字典中不存在的項時,就可能會報錯:

>>> dict1
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}
>>> dict1[6]
Traceback (most recent call last):
  File "<pyshell#56>", line 1, in <module>
    dict1[6]
KeyError: 6

這樣的使用者體驗就會不好。

因此使用get()內建函式。

>>> dict1.get(5)
'five'
>>> dict1.get(6)
>>> print(dict1.get(6))
None

也可以在get中為不存在的項輸出相應的提示:

>>> dict1.get(6, '不存在')
'不存在'
>>> dict1.get(5,  '不存在')
'five'
>>> dict1
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}

如果不知道一個鍵是否在字典中(不能查詢值),可以使用成員資格操作符來進行判斷。in 和 not in

>>> 6 in dict1
False
>>> 5 in dict1
True
>>> 'five' in dict1
False

清空一個字典,使用clear()方法。

>>> dict1
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}
>>> dict1.clear()
>>> dict1
{}

clear()會完全清除整個字典,即使該字典有多個名字對應:

>>> a = {1: 'one'}
>>> b = a
>>> b
{1: 'one'}
>>> a.clear()
>>> a
{}
>>> b
{}

copy()拷貝,區別於賦值:
>>> a = {1: 'one', 2: 'two', 3: 'three'}
>>> b = a.copy()
>>> c = a
>>> a
{1: 'one', 2: 'two', 3: 'three'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}
>>> c
{1: 'one', 2: 'two', 3: 'three'}
>>> id(a)                                    id() 返回地址,可以發現c和a指向同一個字典
2200132871048
>>> id(b)
2200132857800
>>> id(c)
2200132871048
>>> c[4] = 'four'
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}
>>> c
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}

pop()和popitem(),都是彈出字典中的元素。

>>> a = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a.pop(2)
'two'
>>> a
{1: 'one', 3: 'three', 4: 'four'}
>>> a = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a.popitem()
(1, 'one')
>>> a
{2: 'two', 3: 'three', 4: 'four'}

pop()是彈出對應鍵的項,返回鍵對應的值,popitem()是隨機從字典彈出項,返回鍵和值的元組。

setdefault()

用法與get()類似,只是如果找不到對應的鍵,會自動新增,值預設為None,也可以給值。

>>> a = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a.setdefault(2)
'two'
>>> a.setdefault(5)
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: None}
>>> a.setdefault(5, 'five')
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: None}
>>> a.setdefault(6, 'six')
'six'
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: None, 6: 'six'}

update(),用一個字典或對映關係去更新一個字典。

>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: None, 6: 'six'}
>>> b = {2: 'double'}
>>> a.update(b)
>>> a
{1: 'one', 2: 'double', 3: 'three', 4: 'four', 5: None, 6: 'six'}