1. 程式人生 > >如何優雅的生成及遍歷python嵌套字典

如何優雅的生成及遍歷python嵌套字典

切換 sub 目前 stream lec 如果 ati 數據 items

嵌套字典生成

方法一:定義類


class Vividict(dict):

def __missing__(self, key):

value = self[key] = type(self)()

return value

解釋:

  • 第一行:class後面緊接著是類名,即Vividict,類名通常是大寫開頭的單詞,緊接著是(dict),表示該類是dict類繼承下來的。

我們可以使用dir(dict)查看dict的方法

In[22]: print(dir(dict))

[‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__delitem__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__setitem__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘clear‘, ‘copy‘, ‘fromkeys‘, ‘get‘, ‘items‘, ‘keys‘, ‘pop‘, ‘popitem‘, ‘setdefault‘, ‘update‘, ‘values‘]

同理,可以查看Vividict的方法

In[23]: print(dir(Vividict))

[‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__delitem__‘, ‘__dict__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__missing__‘, ‘__module__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__setitem__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘clear‘, ‘copy‘, ‘fromkeys‘, ‘get‘, ‘items‘, ‘keys‘, ‘pop‘, ‘popitem‘, ‘setdefault‘, ‘update‘, ‘values‘]

比較兩者可以發現,Vividict的方法比dict的方法多了一個missing方法,也就是我們添加的方法。所以這就是繼承,繼承最大的好處是子類獲得了父類的全部功能,而不必重新造輪子。

  • 第二行:python魔法方法中的自定義序列,類似於定義一個函數。missing在字典的子類中使用,它定義了當試圖訪問一個字典中不存在的鍵時的行為(目前為止是指字典的實例,例如我有一個字典 d , “george” 不是字典中的一個鍵,當試圖訪問 d[‘george’] 時就會調用 d.missing(“george”),結果為{} )。

  • 第三行,第四行:訪問字典中不存在的鍵(key)時,返回空字典作為其返回值(value)

例如:

In[17]: a = dict()

In[18]: type(a)()

Out[18]:

{}

註意:

  • 特殊方法“missing”前後有兩個下劃線!!!
  • 和普通的函數相比,在類中定義的函數只有一點不同,就是第一個參數永遠是實例變量self,並且,調用時,不用傳遞該參數。除此之外,類的方法和普通函數沒有什麽區別,所以,你仍然可以用默認參數、可變參數、關鍵字參數和命名關鍵字參數。

使用:


# coding=utf-8

#導入模塊

import os, openpyxl

import pprint

from pandas import DataFrame

#pprint模塊可以輸出漂亮的字典結構,但是不利於後期利用R作圖

#DataFrame可以將字典結構轉為數據框輸出,方便後期利用R作圖

#切換工作路徑

os.chdir(r‘F:\pycharm_project\mutation_count‘)

#讀取excel表格

wb = openpyxl.load_workbook(‘東方肝膽數據綜合.xlsx‘)

sheet = wb.active

#定義類

class Vividict(dict):

def __missing__(self, key):

value = self[key] = type(self)()

return value

#實例化

d = Vividict()

#字典初始化,賦初值0

for i in range(2,sheet.max_row+1):

d[sheet.cell(row=i, column=1).value][sheet.cell(row=i, column=15).value] = 0

#累加統計各個樣本各種突變類型的數目

for i in range(2,sheet.max_row+1):

d[sheet.cell(row=i, column=1).value][sheet.cell(row=i, column=15).value] +=1

pprint.pprint(d)

#輸出字典結構

pprint.pprint(d)

{‘PDC1279A_vs_PDC1279‘: {‘UTR3‘: 9,

‘UTR5‘: 4,

‘downstream‘: 5,

‘exonic‘: 149,

‘intergenic‘: 170,

‘intronic‘: 163,

‘ncRNA_exonic‘: 17,

‘ncRNA_intronic‘: 23,

‘splicing‘: 2,

‘upstream;downstream‘: 2},

‘PDC1279C_vs_PDC1279‘: {‘UTR3‘: 11,

‘UTR5‘: 13,

‘downstream‘: 1,

‘exonic‘: 174,

‘intergenic‘: 189,

‘intronic‘: 172,

‘ncRNA_exonic‘: 24,

‘ncRNA_intronic‘: 36,

‘splicing‘: 4,

‘upstream‘: 2,

‘upstream;downstream‘: 2}}

#輸出數據框結構,缺損的元素用 NaN補齊

frame = DataFrame(d)

print(frame)

PDC1279A_vs_PDC1279 PDC1279C_vs_PDC1279 \

UTR3 9.0 11.0

UTR5 4.0 13.0

downstream 5.0 1.0

exonic 149.0 174.0

exonic;splicing NaN NaN

intergenic 170.0 189.0

intronic 163.0 172.0

ncRNA_exonic 17.0 24.0

ncRNA_intronic 23.0 36.0

ncRNA_splicing NaN NaN

splicing 2.0 4.0

upstream NaN 2.0

upstream;downstream 2.0 2.0

方法二:使用defaultdict()

兩個維度字典:


from collections import defaultdict

d = defaultdict(defaultdict)

d[1][2] = 3

等價於:


from collections import defaultdict

def nested_dict_factory():

return defaultdict(int)

def nested_dict_factory2():

return defaultdict(nested_dict_factory)

db = defaultdict(nested_dict_factory2)

當然,第一種方法簡潔的多!

要獲得更多維度,你可以(三維):


from collections import defaultdict

d = defaultdict(lambda :defaultdict(defaultdict))

d[1][2][3] = 4

使用defaultdict任何未定義的key都會默認返回一個根據method_factory參數不同的默認值, 而相同情況下dict()會返回KeyError.

python中lambda存在意義就是對簡單函數的簡潔表示

實際上 defaultdict也是通過missing方法實現的。defaultdict在dict的基礎上添加了一個missing(key)方法, 在調用一個不存的key的時候, defaultdict會調用missing, 返回一個根據default_factory參數的默認值, 所以不會返回Keyerror.


In[35]: print(dir(defaultdict))

[‘__class__‘, ‘__contains__‘, ‘__copy__‘, ‘__delattr__‘, ‘__delitem__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__missing__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__setitem__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘clear‘, ‘copy‘, ‘default_factory‘, ‘fromkeys‘, ‘get‘, ‘items‘, ‘keys‘, ‘pop‘, ‘popitem‘, ‘setdefault‘, ‘update‘, ‘values‘]

嵌套字典的遍歷

方法一:一層一層的嵌套叠代,從而實現遍歷


for key,value in d.items():

for key2, val2 in value.items():

print (key2, val2)

在類中定義walk方法實現嵌套字典的遍歷


class Vividict(dict):

def __missing__(self, key):

value = self[key] = type(self)()

return value

def walk(self):

for key, value in self.items():

if isinstance(value, Vividict):

for tup in value.walk():

yield (key,) + tup

else:

yield key, value

解釋:
第1-4行:上面已經解釋過了
第5-11行:定義一個walk函數,並對字典items對象的key和value進行遍歷,isinstance用於判斷對象類型,如果value是一個字典,那麽對value調用walk()方法繼續進行遍歷,一層一層將key,value存儲在元祖中()。當最裏面一層,即else情況,輸出key,value。整個過程即將字典數據結構扁平化為元祖

此時,我們可以這樣來遍歷字典(輸出元祖)

#打印整個元祖

for tup in d.walk():

print(tup)

(‘PDC1279_vs_PDC1279C6‘, ‘downstream‘, 3)

(‘PDC1279_vs_PDC1279C6‘, ‘UTR3‘, 11)

(‘PDC1279_vs_PDC1279C6‘, ‘intronic‘, 164)

(‘PDC1279_vs_PDC1279C6‘, ‘splicing‘, 4)

**這就是扁平化的字典**

#打印元祖的第3列

for tup in d.walk():

print(tup[2])

參考

(1)https://ask.helplib.com/229754

(2)Python魔法方法指南(推薦閱讀)

http://pyzh.readthedocs.io/en/latest/python-magic-methods-guide.html

如何優雅的生成及遍歷python嵌套字典