在Python中初始化/创建/填充Dict的Dict

时间:2013-02-28 23:32:57

标签: python dictionary

我以前在python中使用过字典但是我还是python的新手。这次我使用字典词典的字典...即三层字典,并想在编程之前检查。

我想将所有数据存储在这个三层dict中,并且想知道什么是一个很好的pythonic方式来初始化,然后读取一个文件并写入这样的数据结构。

我想要的字典属于以下类型:

{'geneid':
{'transcript_id':
{col_name1:col_value1, col_name2:col_value2}
}
}

数据属于这种类型:

geneid\ttx_id\tcolname1\tcolname2\n
hello\tNR432\t4.5\t6.7
bye\tNR439\t4.5\t6.7

关于如何以良好的方式做到这一点的任何想法?

谢谢!

3 个答案:

答案 0 :(得分:4)

首先,让我们从csv模块开始处理解析这些行:

import csv
with open('mydata.txt', 'rb') as f:
    for row in csv.DictReader(f, delimiter='\t'):
        print row

这将打印:

{'geneid': 'hello', 'tx_id': 'NR432', 'col_name1': '4.5', 'col_name2': 6.7}
{'geneid': 'bye', 'tx_id': 'NR439', 'col_name1': '4.5', 'col_name2': 6.7}

所以,现在你只需要将它重新组织成你喜欢的结构。这几乎是微不足道的,除了你必须处理的事实是,当你第一次看到给定的geneid时,你必须为它创建一个新的空dict,同样这是你第一次看到它tx_id内的给定geneid。您可以使用setdefault解决该问题:

import csv
genes = {}
with open('mydata.txt', 'rb') as f:
    for row in csv.DictReader(f, delimiter='\t'):
        gene = genes.setdefault(row['geneid'], {})
        transcript = gene.setdefault(row['tx_id'], {})
        transcript['colname1'] = row['colname1']
        transcript['colname2'] = row['colname2']

您可以使用defaultdict

使其更具可读性
import csv
from collections import defaultdict
from functools import partial
genes = defaultdict(partial(defaultdict, dict))
with open('mydata.txt', 'rb') as f:
    for row in csv.DictReader(f, delimiter='\t'):
        genes[row['geneid']][row['tx_id']]['colname1'] = row['colname1']
        genes[row['geneid']][row['tx_id']]['colname2'] = row['colname2']

这里的诀窍是顶级dict是一个特殊的,只要它第一次看到一个新密钥就会返回一个空的dict ......它返回的空dict本身就是空dict。唯一困难的是defaultdict采用返回正确类型对象的函数,返回defaultdict(dict)的函数必须使用partiallambda编写或显式函数。 (如果你愿意的话,ActiveState上的配方和PyPI上的模块将为你提供更加通用的版本,根据需要创建新的词典。)

答案 1 :(得分:2)

我也在尝试寻找替代方案,并在stackoverflow中提出了这个很好的答案:

What's the best way to initialize a dict of dicts in Python?

基本上就我而言:

class AutoVivification(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

答案 2 :(得分:2)

我必须经常编写我的研究代码。您将需要使用defaultdict包,因为它允许您通过简单的赋值在任何级别添加键:值对。我会在回答你的问题后告诉你。这是直接来自我的一个程序。专注于最后4行(不是注释)并通过块的其余部分跟踪变量以查看它正在做什么:

from astropy.io import fits #this package handles the image data I work with
import numpy as np
import os
from collections import defaultdict

klist = ['hdr','F','Ferr','flag','lmda','sky','skyerr','tel','telerr','wco','lsf']
dtess = []

for file in os.listdir(os.getcwd()):
    if file.startswith("apVisit"):
        meff = fits.open(file, mode='readonly', ignore_missing_end=True)
        hdr = meff[0].header
        oid = str(hdr["OBJID"]) #object ID
        mjd = int(hdr["MJD5"].strip(' ')) #5-digit observation date
        for k,v in enumerate(klist):
            if k==0:
                dtess = dtess+[[oid,mjd,v,hdr]]
            else:
                dtess=dtess+[[oid,mjd,v,meff[k].data]]
        #header extension works differently from the rest of the image cube
        #it's not relevant to populating dictionaries
#HDUs in order of extension no.: header, flux, flux error, flag mask, 
# wavelength, sky flux, error in sky flux, telluric flux, telluric flux errors,
# wavelength solution coefficients, & line-spread function
dtree = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
for s,t,u,v in dtess:
    dtree[s][t][u].append(v)
#once you've added all the keys you want to your dictionary, 
#set default_factory attribute to None 
dtree.default_factory = None

这是摘要版本。

  1. 首先,对于n级字典,您必须进行排序和转储 所有内容都放在[key_1,key_2,形式]中的(n + 1)个元组列表中 ...,key_n,value]。
  2. 然后,要初始化n级词典, 你只需输入“defaultdict(lambda:”(减去引号)n-1次, 最后粘贴“defaultdict(list)”(或其他一些数据类型),和 关闭括号。
  3. 使用for循环附加到列表中。 *注意:当您去访问数据值时 在最低级别,您可能需要输入my_dict [key_1] [key_2] [...] [key_n] [0]获取实际值而不仅仅是数据描述 在其中输入。
  4. *编辑:当你的字典大到你想要的字体时,设置 default_factory属性为None。
  5. 如果您尚未将default_factory设置为None,则可以稍后通过键入my_dict [key_1] [key_2] [...] [new_key] = new_value或使用append()等内容添加到嵌套字典中命令。您甚至可以添加其他词典,只要您通过这些分配形式添加的词典不会自己嵌套。

    * 警告!新添加的代码段的最后一行是超级重要,其中default_factory属性设置为None。你的PC需要知道你什么时候添加到你的字典,否则它可能会继续在后台分配内存以防止buffer overflow,吃掉你的RAM,直到程序停止运行。这是一种memory leak。在我写完这个答案后的一段时间里,我学到了很多东西。这个问题困扰了我几个月,我甚至不认为我最终会弄明白,因为我对内存分配一无所知。