1. 程式人生 > 其它 >python在字典中插入新的資料_python新知識 字典檢視

python在字典中插入新的資料_python新知識 字典檢視

技術標籤:python在字典中插入新的資料在定時器中返回給檢視的值

python新知識字典檢視

從bug中學習:字典返回的居然是檢視

bug

與之前相同,我在試圖從dataframeseries中提取值。

samples = ['R1','R2','R3','R4']df = pd.DataFrame([[True,False,False,True]],columns=samples)series = pd.Series({'R1':True,'R2':False,'R3':False,'R4':True})print(df[samples])print(series[samples])

out:

     R1     R2     R3    R40  True  False  False  TrueR1     TrueR2    FalseR3    FalseR4     Truedtype:bool

正常。

但是呢,我在實際程式碼中用到的samples是一個字典。

samples = {'R1':'R1','R2':'R2','R3':'R3','R4':'R4'}  #鍵值相等,僅供演示print(df[samples.keys()])print(series[samples.keys()])

out:

     R1     R2     R3    R40  True  False  False  TrueR1     TrueR2    FalseR3    FalseR4     Truedtype: bool

還正常,別急,bug來了。

print(df[samples_map.values()])print(series[samples_map.values()])

out:

     R1     R2     R3    R40  True  False  False  TrueKeyError                                  Traceback (most recent call last)-44-c2d1464b8ebd>       1 print(df[samples.values()])----> 2 print(series[samples.values()])KeyError: dict_values(['R1', 'R2', 'R3', 'R4'])

錯誤,而且是取值的鍵錯誤,鍵值是dict_values(['R1', 'R2', 'R3', 'R4']),what?

這時候可能就要問了,這突然出現的是dict_values是什麼鬼東西。為什麼取keys正常,取values就錯誤呢?

keysvalues都輸出看看。

print(samples.keys())print(samples.values())

out:

dict_keys(['R1', 'R2', 'R3', 'R4'])dict_values(['R1', 'R2', 'R3', 'R4'])

啊,返回的是dict_keysdict_values類的物件,不是列表。

字典檢視

那我們就來研究一下這兩個類。

查閱stackoverflow[1]和python官方文件[2]後得知,dict.keys(),dict.values()dict.items()返回的都是檢視物件。他們能夠提供字典記錄的動態檢視,當字典變化時,檢視也會變化。檢視可以通過遍歷產生相應的資料,並支援成員測試。

檢視支援如下操作:

len(dictview)iter(dictview)x in dictviewreversed(dictview)for loop

dict.keys()返回的鍵檢視是類似集合的,因為鍵記錄的值是唯一併且可hash的。如果所有的值都可hash,那麼鍵值對也是唯一且可hash的,dict.items()鍵值對檢視也是類似集合的。dict.values()值檢視通常不被作為類似集合的物件處理,因為值記錄通常不唯一。

對於類似集合的檢視,所有抽象基礎類collections.abc.Set定義的操作符都是可以進行的,比如==<或者^

來一個直觀的例子。

dishes = { 'sausage': 1, 'bacon': 1, 'spam': 500}keys = dishes.keys()       # 取出keysvalues = dishes.values()   # 取出valuesdel dishes['spam']dishes['eggs'] = 2print(list(keys))print(list(values))

out:

['sausage', 'bacon', 'eggs'][1, 1, 2]

仔細看一下,我明明事先取出了keysvalues,然後刪除字典的一個鍵值對和新增鍵值對後,取出的keysvalues居然也跟隨著發生了動態變化。希望你能從這個例子中更好的理解什麼叫檢視。

動態變化會避免以下錯誤發生。

dishes = { 'sausage': 1, 'bacon': 1, 'spam': 500}keys = list(dishes.keys())     #使用list模擬python2del dishes['spam']dishes['eggs'] = 2for i in keys:    print(i,dishes[i])

out:

sausage 1bacon 1---------------------------------------------------------------------------KeyError                                  Traceback (most recent call last)-127-e0e39cb366d4>       4 dishes['eggs'] = 2      5 for i in keys:----> 6     print(i,dishes[i])KeyError: 'spam'

不加list時。

dishes = { 'sausage': 1, 'bacon': 1, 'spam': 500}keys = dishes.keys()     del dishes['spam']dishes['eggs'] = 2for i in keys:    print(i,dishes[i])

out:

sausage 1bacon 1eggs 2

長度、成員測試、迭代器、集合運算的例子。

print('eggs' in keys)print(len(keys))print(next(iter(keys)))                  #iter使用可迭代物件生成迭代器,next進行迭代器取值print(keys & {'eggs', 'bacon', 'salad'}) #交集print(keys | {'sausage', 'juice'})       #並集

out:

True3sausage{'eggs', 'bacon'}{'bacon', 'eggs', 'juice', 'sausage'}

檢視的優點在於能夠直接計算長度、進行成員測試且跟隨字典動態變化。

思考

那檢視和之前的bug有什麼關係呢。從官方文件可以看出,keys檢視和values檢視的唯一區別在於,keys裡的值可hash,而values裡的值預設不可hash

但是更奇怪的事發生了。

hash(samples.keys())

out:

---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last)input----> 1 hash(samples.keys())TypeError:unhashabletype:'dict_keys'
hash(samples.values())

out:

-9223371939388789928

values檢視物件整體居然可hash,而且官方說d.values() == d.values()恆為False。啊這,不會是因為hash值可變吧,再來一次。

hash(samples.values())

out:

-9223371939388789799

果然每次值都不一樣。

不過,真的不知道values檢視物件可hash是為了什麼,反倒是如果keys檢視物件可hash我倒是能理解。

與此同時,pandas官方文件[3]中說。

An Index instance canonlycontain hashable objects

index只能包含可hash物件,而且之前的錯誤詳細資訊裡也有部分提到了hashable(之前省略了)。

pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_value()pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_value()pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_loc()pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()KeyError: dict_values(['R1', 'R2', 'R3', 'R4'])

所以有可能是因為values檢視物件可hash導致series認為該返回值是一個單獨的鍵,而不是多個鍵的集合,於是series直接提取該鍵的對應值,從而產生錯誤。

fix bug

解決起來當然很簡單了。

print(series[list(samples.values())])print(series[iter(samples.values())])

out:

R1     TrueR2    FalseR3    FalseR4     Truedtype: boolR1     TrueR2    FalseR3    FalseR4     Truedtype:bool

但是我又發現,使用.loc也可以解決該bug。

print(series.loc[samples.values()])

out:

R1     TrueR2    FalseR3    FalseR4     Truedtype: bool

.loc就可以識別出該返回值包含多值並逐個取值,但是直接[]卻不行。難道是因為.loc優先檢驗提供的值是否可迭代?

本文涉及內容過於複雜,結論僅為猜想。歡迎提出意見。

我是SSSimon Yang,關注我,用code解讀世界

3a055b55aecade2b031bb9a8d2fb052b.png

References

[1]stackoverflow:https://stackoverflow.com/questions/8957750/what-are-dictionary-view-objects[2]python官方文件:https://docs.python.org/3/library/stdtypes.html#dictionary-view-objects[3]pandas官方文件:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html