嵌套字典生成
方法一:定義類
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