在python dict中赋值(复制与参考) [英] assigning value in python dict (copy vs reference)

查看:44
本文介绍了在python dict中赋值(复制与参考)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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,

<代码>>>a_dict = b_dict = c_dict = {}

这将创建一个空字典并且所有变量都指向这个 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.

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

会给

{'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

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

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中,与list相比,strinttuple是一些内置的不可变类型dict(和其他)是可变类型.immutable 对象是一旦创建就无法更改的对象.因此,在您的示例中:

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

a = b = c = 1

在那一行之后,所有abc都引用了内存中的同一个整数(你可以通过打印它们各自的id 并注意它们是相同的).但是,当您这样做时:

After that line, all a, b and c refer 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:

a += 1

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

a now 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.

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

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:

name = something

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

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:

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

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

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.

这篇关于在python dict中赋值(复制与参考)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆