【问题标题】:Python dictionary is somehow updatingPython字典以某种方式更新
【发布时间】:2013-12-26 21:47:06
【问题描述】:

我已尽力解决这个问题,但我一辈子都做不到。我有一本包含许多不同值的字典,包括另一本字典。在为字典中的字典设置值之前,我尝试将值设置为等于“空白”字典,以便在后续步骤中更新它。

简短的故事是:我有两行以某种方式改变了我没想到的字典。给定一些听写: blankresiduedict = {stuff:[stuff], stuff:[stuff]}; blankidentifiers = {stuff:stuff, stuff:stuff}

线条

self.pdb_chain_dict['1MH9_B'] = (blankresiduedict.copy(),blankidentifiers.copy())
self.pdb_chain_dict['1MH9_B'][0][(stuff)][0] = residuedict[('A','D','41')]

正在以某种方式将blankresiduedict的值更改为等于residualdict。

知道这是怎么回事吗?在该代码段中实际上没有其他对 blankresiduedict 的引用,当我查看输出时,blankresiduedict 开始时是准确的,然后随着每个循环不断更改值以等于该循环的任何残留字典。



(下面是更详细的说明)

这是一个非常大的项目的一小部分,因此其中一些可能真的很难以紧凑的形式表示。我会尽我所能消除不必要的东西。这是一个类中的一个方法,我试图用它来更新类实例的字典。

blankresiduedict = {}
blankidentifiers = {}
self.allowmultiples = True
self.ancestorline = [
    '1MH9', 
    'A', 'D', '41',
    'A', 'D', '43',
    'A', 'T', '130', 
    #etc...
]
self.no_key_residues = 6
self.pdb_chain_dict = {
    '1MH9_B': (
        {
            ('A','D','41'): [('B','D','41')],
            ('A','D','43'): [('B','D','43')], 
            ('A','T','130'): [('B','T','130')]
        }, 
        #{identifiers dictionary}
    ), 
    '1MH9_C': (
        #{etc},{etc}
    ), 
    # etc...
}


for i in range(1, (3*self.no_key_residues)+1, 3): # Using this loop structure allows a variable number of key residues to be given
    if not self.allowmultiples:
        raise Exception("Do some stuff here")
    else:
        blankresiduedict[(self.ancestorline[i],self.ancestorline[i+1],self.ancestorline[i+2])] = [('-','-','-')] 
blankidentifiers = {'EC Num':'-','Sprot':'-','Class':'-','Keywords':'-','Title':'-','SeqRepr':'-'}

### Begin some loop structure, where for every loop, the following is basically happening
residuedict = {
    ('A','D','41'): ('B','D','10'), 
    ('A','D','43'): ('B','D','12')
} #in actuality this value would change for every loop, but just showing what a typical loop would look like
self.pdb_chain_dict['1MH9_B'] = (blankresiduedict.copy(),blankidentifiers.copy())
self.pdb_chain_dict['1MH9_B'][0][('A','D','41')][0] = residuedict[('A','D','41')]

这里应该发生的是 pdb_chain_dict 中的值设置为两个空白字典 ({residuedict},{identifiers})同样的问题。但是,我发现blankresiduedict 实际上正在发生变化。而且,经过大量测试,它正在改变的行是self.pdb_chain_dict['1MH9_B'][0][('A,'D','41')][0] = residuedict[('A','D','41')]

这对我来说毫无意义...blankresiduedict 甚至没有涉及,但不知何故,它的价值在该步骤中被改变了。

【问题讨论】:

    标签: python python-3.x dictionary


    【解决方案1】:

    这是因为字典的副本不是深层副本,而且您的字典值是可变的列表。这是重现您的问题的最小示例:

    d1 = {"foo": [1, 2, 3]}
    d2 = d1.copy()
    # Add a new element to d2 to show that the copy worked
    d2["bar"] = []
    
    # The two dicts are different.
    print d1
    print d2
    
    # However, the list wasn't copied 
    # it's the same object that shows up in 2 different dicts
    print d1["foo"] is d2["foo"]
    
    # So that's what happens in your code: you're mutating the list.
    d1["foo"].append(5)
    print d2["foo"]
    

    【讨论】:

    • 哦,哇,我没有意识到这一点。这很好地说明了副本如何不“深”,但是如何在保留列表的同时生成正版副本?我刚刚尝试过的一种方法是为每个循环“重新创建”空白字典,这样它们就不会被有效地重写。然而,这感觉不像是一种非常“Pythonic”的处理方式。
    • 问题不在于字典本身,而在于它包含的列表。我建议重新创建列表而不是改变它,例如d2["foo"] = [1, 2, 3, 5] 在我的示例中,或在您的示例中重建 self.pdb_chain_dict['1MH9_B'][0][('A,'D','41')]。或者,deepcopy 模块,顾名思义,会进行深度复制,但我觉得它的使用令人反感。
    • 我会使用copy.deepcopy(或一切都是可变的语言)。
    • @sweeneyrod:请注意,在这种情况下,可变性是首先出现问题的原因;)
    • @MaxNoel 是的,我的意思是不可变的!
    猜你喜欢
    • 2010-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-09
    • 2014-09-21
    • 1970-01-01
    相关资源
    最近更新 更多