在python dict中赋值(复制与参考)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23852480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 03:32:06  来源:igfitidea点击:

assigning value in python dict (copy vs reference)

pythonreference

提问by darkryder

I understand that in python every thing, be it a number, string, dict or anything is an object. The variable name simply points to the object in the memory. Now according to this question,

我知道在 python 中,每一件事,无论是数字、字符串、字典还是任何东西都是一个对象。变量名只是指向内存中的对象。现在根据这个问题

>> a_dict = b_dict = c_dict = {}

>> a_dict = b_dict = c_dict = {}

This creates an empty dictionary and all the variables point to this dict object. So, changing any one would be reflected in the other variables.

这将创建一个空字典并且所有变量都指向这个 dict 对象。因此,更改任何一个都会反映在其他变量中。

>> a_dict["key"] = "value" #say
>> print a_dict
>> print b_dict
>> print c_dict

would give

会给

{'key': value}
{'key': value}
{'key': value}

I had understood the concept of variables pointing to objects, so this seems fair enough.

我已经理解了指向对象的变量的概念,所以这似乎很公平。

Now even though it might be weird, since its such a basic statement, why does this happen ?

现在即使它可能很奇怪,因为它是一个如此基本的陈述,为什么会发生这种情况?

>> a = b = c = 1
>> a += 1
>> print a, b, c
2, 1, 1   # and not 2, 2, 2

First part of question:Why isn't the same concept applied here ?

问题的第一部分:为什么这里不应用相同的概念?

Actually this doubt came up when I was trying to search for a solution for this:

实际上,当我试图为此寻找解决方案时,出现了这个疑问:

>> a_dict = {}
>> some_var = "old_value"
>> a_dict['key'] = some_var
>> some_var = "new_value"
>> print a_dict
{'key': 'old_value'}  # and not {'key': 'new_value'}

This seemed counter-intuitive since I had always assumed that I am telling the dictionary to hold the variable, and changing the object that the variable was pointing to would obviously reflect in the dictionary. But this seems to me as if the value is being copied, not referenced. This was the second thing I didn't understand.

这似乎违反直觉,因为我一直认为我是在告诉字典保存变量,而更改变量指向的对象显然会反映在字典中。但这在我看来好像是复制而不是引用值。这是我不明白的第二件事。

Moving on, i tried something else

继续,我尝试了别的东西

>> class some_class(object):
..    def __init__(self):
..        self.var = "old_value"
>> some_object = some_class()
>> a_dict = {}
>> a_dict['key'] = some_object
>> some_object.var = "new_value"
>> print a_dict['key'].var
"new_value"    # even though this was what i wanted and expected, it conflicts with the output in the previous code

Now, over here, obviously it was being referenced. These contradictions has left me squacking at the unpredictable nature of python, even though I still love it, owing to the fact I don't know any other language well enough :p . Even though I'd always imagined that assignments lead to reference of the object, however these 2 cases are conflicting.So this is my final doubt . I understand that it might be one those python gotcha's . Please educate me.

现在,在这里,显然它被引用了。这些矛盾让我对 python 的不可预测性感到不满,尽管我仍然喜欢它,因为我对任何其他语言都不太了解 :p 。尽管我一直认为赋值会导致对象的引用,但这两种情况是相互矛盾的。所以这是我最后的怀疑。我知道这可能是那些 python gotcha 的. 请教育我。

采纳答案by mgilson

You're wrestling with 2 different things here. The first is the idea of mutabilityvs. immutability. In python, str, int, tupleare some of the builtin immutable types compared to list, dict(and others) which are mutable types. immutableobjects are ones which cannot be changed once they are created. So, in your example:

你在这里与 2 种不同的东西搏斗。第一个是可变性不变性的想法。在 python 中strint,tuple是一些内置的不可变类型,而list, dict(和其他)是可变类型。 不可变对象是一旦创建就无法更改的对象。所以,在你的例子中:

a = b = c = 1

After that line, all a, band crefer to the same integer in memory (you can check by printing their respecitve id's and noting that they are the same). However, when you do:

该行后,所有的abc指在内存中相同的整数(你可以打印他们的respecitve检查id的,并指出,它们是相同的)。但是,当您这样做时:

a += 1

anow refers to a new (different) integer at a different memory location. Note that as a convention, +=should return a new instance of something if the type is immutable. If the type is mutable, it should change the object in place and return it. I explain some of the more gory detail in this answer.

a现在指的是不同内存位置的新(不同)整数。请注意,作为约定,+=如果类型是不可变的,则应返回某个新实例。如果类型是mutable,它应该改变对象并返回它。我在这个答案中解释了一些更血腥的细节。



For the second part, you're trying to figure out how python's identifiers work. The way that I think of it is this... when you write a statement:

对于第二部分,您将尝试弄清楚 Python 的标识符是如何工作的。我的想法是这样的......当你写一个声明时:

name = something

The right hand side is evaluated into some object (an integer, string, ...). That object is then given the name on the left hand side1. When a name is on the right hand side, the corresponding object is automatically "looked up" and substituted for the name in the calculation. Note that in this framework, assignment doesn't care if anything had that name before -- it simply overwrites the old value with the new one. Objects which were previously constructed using that name don't see any changes -- either. They've already been created -- keeping references to the objects themselves, not the names. So:

右侧被评估为某个对象(整数,字符串,...)。然后在左侧1为该对象命名。当名称在右侧时,相应的对象会自动“查找”并替换计算中的名称。请注意,在此框架中,赋值并不关心之前是否有任何名称 - 它只是用新值覆盖旧值。以前使用该名称构造的对象也看不到任何更改。它们已经被创建——保持对对象本身的引用,而不是名称。所以:

a = "foo"  # `a` is the name of the string "foo" 
b = {"bar": a}  # evaluate the new dictionary and name it `b`.  `a` is looked up and returns "foo" in this calculation
a = "bar"  # give the object "bar" the name `a` irrespecitve of what previously had that name

1I'm glossing over a few details here for simplicity -- e.g. what happens when you assign to a list element: lst[idx] = some_value * some_other_value.

1为简单起见,我在这里忽略了一些细节——例如,当您分配给列表元素时会发生什么: lst[idx] = some_value * some_other_value.

回答by Sukrit Kalra

This is because +=can be interpreted as a = a + 1, which rebinds the variable ato the value a + 1, that is, 2.

这是因为+=可以解释为a = a + 1,它将变量a重新绑定到值a + 1,即2

Similarly, some_var = "new_value"rebinds the variable and the object is not changed, so the key, value pair in the dictionary still points to that object.

同理,some_var = "new_value"重新绑定变量,对象不变,所以字典中的键值对仍然指向那个对象。

In your last example, you are not rebinding, but mutating the object, so the value is changed in the dictionary.

在您的最后一个示例中,您不是重新绑定,而是更改对象,因此字典中的值已更改。