Python循环字典值引用更新所有值

4 投票
1 回答
1180 浏览
提问于 2025-04-17 15:27

我在用Python更新字典里的值时遇到了问题。我想更新一个嵌套值(可以是整数或列表),这个值是针对某个第一层级的键,但结果却把所有第一层级的键的值都更新了。

我先创建了这个字典:

kmerdict = {}
innerdict = {'endcover':0, 'coverdict':{}, 'coverholder':[], 'uncovered':0, 'lowstart':0,'totaluncover':0, 'totalbases':0}
for kmer in kmerlist: # build kmerdict
    kmerdict [kmer] = {}
    for chrom in fas:  #open file and read line
        chromnum = chrom[3:-3]
        kmerdict [kmer][chromnum] = innerdict

然后我从一个列表中遍历染色体(这些是普通的文本文件,列表叫fas,没显示出来),并把7个字符的字符串(k=7)当作键。如果这个键在我想要查找的键的列表(kmerlist)中,我就试图用它来引用字典中一个嵌套的单一值:

for chrom in fas:  #open file and read line
    chromnum = chrom[3:-3]
    p = 0  #chromosome position counter
    thisfile = "/var/store/fa/" + chrom
    thischrom = open(thisfile)
    thischrom.readline()
    thisline = thischrom.readline()
    thisline = string.strip(thisline.lower())
    l=0  #line counter
    workline = thisline
    while(thisline):
        if len(workline) > k-1:
            thiskmer = ''
            thiskmer = workline[0:k] #read five bases
            if thiskmer in kmerlist:
                thisuncovered = kmerdict[thiskmer][chromnum]['uncovered']
                thisendcover =  kmerdict[thiskmer][chromnum]['endcover']
                thiscoverholder = kmerdict[thiskmer][chromnum]['coverholder']
                if p >= thisendcover:
                    thisuncovered += (p - thisendcover)
                    thisendcover = ((p+k) + ext)
                    thiscoverholder.append(p)
                elif p < thisendcover:
                    thisendcover = ((p+k) + ext)
                    thiscoverholder.append(p)
            print kmerdict[thiskmer]
            p += 1
            workline = workline[1:]
        else:
            thisline = thischrom.readline()
            thisline = string.strip(thisline.lower())
            workline = workline+thisline
            l+=1
print kmerdict

但是当我打印字典时,所有“thiskmer”层级的值都被更新成了相同的值。我对字典不太熟悉,看不出我哪里出错了,但问题很严重!有没有人能帮我解答一下?

希望我说得够清楚。我已经在这段代码上纠结太久了 :(

1 个回答

3

坦白说 -- 我没有花时间去弄懂你所有的代码 -- 只看了前面的部分。你遇到的第一个问题是在设置部分:

kmerdict = {}
innerdict = {'endcover':0, 'coverdict':{}, 'coverholder':[], 'uncovered':0, 
             'lowstart':0,'totaluncover':0, 'totalbases':0}
for kmer in kmerlist: # build kmerdict
    kmerdict [kmer] = {}
    for chrom in fas:  #open file and read line
        chromnum = chrom[3:-3]
        kmerdict [kmer][chromnum] = innerdict

你只创建了一次 innerdict,然后就一直使用同一个字典。换句话说,每次 kmerdict[kmer][chromnum] 都指向的是同样的对象。也许把最后一行改成:

kmerdict [kmer][chromnum] = copy.deepcopy(innerdict)

会有帮助(记得在文件顶部适当引入 copy)?另外,你也可以把 innerdict 的创建放到内层循环里,就像评论中提到的那样:

def get_inner_dict():
    return {'endcover':0, 'coverdict':{}, 'coverholder':[], 'uncovered':0, 
            'lowstart':0,'totaluncover':0, 'totalbases':0}

kmerdict = {}
for kmer in kmerlist: # build kmerdict
    kmerdict [kmer] = {}
    for chrom in fas:  #open file and read line
        chromnum = chrom[3:-3]
        kmerdict [kmer][chromnum] = get_inner_dict()

-- 我决定用一个函数来让代码更容易阅读 :).

撰写回答