如果python中的dicts是可变的,为什么编辑第二个字典中包含的字典不会改变第二个字典?

时间:2017-12-10 09:23:11

标签: python python-3.x dictionary immutability mutable

我是python的新手,我只是在学习不可变和可变对象(我之前从未遇到过这种情况,我在MATLAB和C#中的编码经验有限。)

我想知道为什么,如果python中的dicts是可变的,编辑第二个dict中包含的dict不会改变第二个dict?

这是一个例子,其中dict(蝙蝠侠)被添加到超级英雄名称(super_hero_names)的字典中。当蝙蝠侠后来改变时,它不会反映在超级英雄名字词典中。如果dicts像字符串一样是不可变的,那对我来说是有意义的,但是它们是可变的,为什么会发生这种情况呢?

super_hero_names = {
    'Superman' : 'Clark Kent',
    'Spiderman' : 'Peter Parker'
}

batman = {'Batman' : 'Bruce'}

super_hero_names.update(batman)

batman['Batman'] = 'Bruce Wayne' # (edited)

print(super_hero_names)

# Output: {'Superman': 'Clark Kent', 'Spiderman': 'Peter Parker', 'Batman': 'Bruce'}

5 个答案:

答案 0 :(得分:2)

可变名称

代码中的问题是字符串是不可变的:您无法将字符串'Bruce'修改为'Bruce Wayne'。你替换它,参考已经消失。如果使用可变对象作为值,则可以获得所需的结果:

class Person:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return repr(self.name)


super_hero_names = {
    'Superman': Person('Clark Kent'),
    'Spiderman': Person('Peter Parker')
}

bruce = Person('Bruce')
batman = {'Batman': bruce}

super_hero_names.update(batman)

bruce.name = 'Bruce Wayne'

print(super_hero_names)
# {'Superman': 'Clark Kent', 'Spiderman': 'Peter Parker', 'Batman': 'Bruce Wayne'}

您在Ruby中的示例

Ruby和Python通常具有非常相似的语法。 Ruby字符串是可变的,因此您的代码可以在Ruby中使用,只需很少的修改:

super_hero_names = {
    'Superman' => 'Clark Kent',
    'Spiderman' => 'Peter Parker'
}

batman = {'Batman' => 'Bruce'}

super_hero_names.update(batman)

batman['Batman'] << ' Wayne' # Mutates the string, doesn't replace it!

print(super_hero_names)
# {"Superman"=>"Clark Kent", "Spiderman"=>"Peter Parker", "Batman"=>"Bruce Wayne"}

答案 1 :(得分:1)

我希望这能解释你的问题。当您更新字典时,它会使用另一个字典的值更新字典,它正在合并。但是当你将一个字典插入其他可变性存在时

super_hero_names = {
    'Superman' : 'Clark Kent',
    'Spiderman' : 'Peter Parker'
}

batman = {'Batman' : 'Bruce'}

super_hero_names['new'] = batman

print(super_hero_names)

batman['Batman'] = 'Bruce Wayne'

print(super_hero_names)

batman = {'Batman' : 'Bruce Wayne'}

print(super_hero_names)

输出

{'Spiderman': 'Peter Parker', 'new': {'Batman': 'Bruce'}, 'Superman': 'Clark Kent'}
{'Spiderman': 'Peter Parker', 'new': {'Batman': 'Bruce Wayne'}, 'Superman': 'Clark Kent'}
{'Spiderman': 'Peter Parker', 'new': {'Batman': 'Bruce Wayne'}, 'Superman': 'Clark Kent'}

答案 2 :(得分:1)

可以通过将名称存储在列表中来实现你想要的东西,但由于额外的间接层,它会使代码更加混乱,效率更低。

super_hero_names = {
    'Superman' : ['Clark Kent'],
    'Spiderman' : ['Peter Parker'],
}

batman = {'Batman' : ['Bruce']}
super_hero_names.update(batman)

batman['Batman'][0] = 'Bruce Wayne'
print(super_hero_names)

<强>输出

{'Superman': ['Clark Kent'], 'Spiderman': ['Peter Parker'], 'Batman': ['Bruce Wayne']}

我们也可以使用

进行更新
batman['Batman'][0] += ' Wayne'

答案 3 :(得分:0)

每次创建字典Function FindLastRow(sht As Worksheet) As Long ' This Function finds the last row in a worksheet, and returns the row number Dim LastCell As Range With sht Set LastCell = .Cells.Find(What:="*", After:=.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, _ searchorder:=xlByRows, searchdirection:=xlPrevious, MatchCase:=False) If Not LastCell Is Nothing Then FindLastRow = LastCell.Row Else MsgBox "Error! worksheet is empty", vbCritical End If End With End Function 时,实际上是在创建字典并将其分配给变量batman

我相信你要做的是:

batman

这种情况下的输出将是:

super_hero_names = {
    'Superman' : 'Clark Kent',
    'Spiderman' : 'Peter Parker'}
batman = {'Batman' : 'Bruce'}
super_hero_names.update(batman)
super_hero_names['Batman'] =  'Bruce Wayne'
print(super_hero_names)

答案 4 :(得分:0)

在这种情况下,update()的行为如下:

for key, value in batman.items():
    super_hero_names[key] = value

此处,super_hero_names.update(batman)首先检查super_hero_names是否具有“蝙蝠侠”键。如果存在,则覆盖(或更新)该值。如果没有,它会创建“蝙蝠侠”,只需将值分配给键。

添加了:

以下是示例代码。我使用list来保存多个超人字典,而不是使用字典作为数据容器。正如您所说,字典是可变的,因此更新方法会修改super_hero_names列表中的内容。

superman = {'Superman' : 'Clark Kent'}
spiderman = {'Spiderman' : 'Peter Parker'}

super_hero_names = [
    superman,
    spiderman
]

batman = {'Batman' : 'Bruce'}
super_hero_names.append(batman)
print(super_hero_names)
# [{'Superman': 'Clark Kent'}, {'Spiderman': 'Peter Parker'}, {'Batman': 'Bruce'}]

batman.update({'Batman': 'test'})

print(super_hero_names)
# [{'Superman': 'Clark Kent'}, {'Spiderman': 'Peter Parker'}, {'Batman': 'test'}]