【问题标题】:Does Python make a copy of objects on assignment?Python 是否会在赋值时复制对象?
【发布时间】:2011-01-27 04:36:32
【问题描述】:

我希望以下代码只会初始化 dict_adict_bdict_c 字典。但它似乎有一个副本通过效果:

dict_a = dict_b = dict_c = {}
dict_c['hello'] = 'goodbye'

print dict_a
print dict_b
print dict_c

如你所见,结果如下:

{'hello': 'goodbye'}
{'hello': 'goodbye'}
{'hello': 'goodbye'}

为什么那个程序会给出之前的结果,我希望它什么时候返回:

{}
{}
{'hello': 'goodbye'}

【问题讨论】:

  • 没有教程,我只是在应用我认为适用于 Java 等语言的概念。

标签: python


【解决方案1】:

我同意上面所说的。这里的关键是,在 Python 中,赋值表示对对象的引用。 我试图自己掌握这个概念,我认为了解在哪种情况下会创建新对象以及何时更改现有对象很重要。

在上面的示例中,行:

dict_c['hello'] = 'goodbye'

不创建新对象。它只改变被dict_a、dict_b和dict_c引用的对象。

如果你写的是:

dict_c = {'hello': 'goodbye'}

它将创建一个新对象,该对象将被 dict_c 引用。 Dict_a 和 dict_b 仍将指向空对象。

在这种情况下,如果你运行:

print dict_a
print dict_b
print dict_c

你会得到:

{}
{}
{'hello': 'goodbye'}

【讨论】:

    【解决方案2】:

    虽然

    >>> dict_a, dict_b, dict_c = {}, {}, {}
    

    在大多数情况下是正确的方法,当它超过 3 时看起来很奇怪

    想象一下

    >>> a, b, c, d, e, f = {}, {}, {}, {}, {}, {}
    

    如果我想初始化超过 3 个东西,我会使用

    >>> a, b, c, d, e, f, = [dict() for x in range(6)]
    

    【讨论】:

    • "注意:不要使用 [{} for x in range(6)]" 为什么不呢?每次迭代都会执行一次元素表达式,每次执行文字 {} 时,它都会返回一个新的字典。事实上,这应该比dict() 更受欢迎,因为它避免了函数调用。
    • @TokenMacGuy,是也不是。现在我重新阅读了我写的内容,我明白了你的意思。 {} 每次都会被初始化。也就是说{} 只是dict() 的语法糖。使用前者不会保存任何内容。
    • 杰弗里·何塞:怀疑托马斯是吗? import dis; print dis.dis(lambda: dict()); print dis.dis(lambda:{})
    • @TokenMacGuy。嗬!在提出任何索赔之前,我应该有dis'd。我的立场是正确的。
    【解决方案3】:

    这是因为在 Python 中,变量(名称)只是对单个对象的引用。当您分配dict_a = dict_b 时,您实际上是在将内存地址(或指针,如果您愿意的话)从dict_b 复制到dict_a。那本字典还有一个实例。

    要获得所需的行为,请使用dict.copy 方法,如果您的字典可能有嵌套字典或其他嵌套对象,请使用copy.deepcopy

    >>> a = {1:2}
    >>> b = a.copy()
    >>> b
    {1: 2}
    >>> b[3] = 4
    >>> a
    {1: 2}
    >>> b
    {1: 2, 3: 4}
    >>> 
    

    【讨论】:

    • 所以字典是对象,如果说整数变量还是这样,还是变量的类型对它是对象没有影响?
    • 整数是不可变的,所以我不确定你打算如何重现这种行为。在任何情况下,某些类型的字面量值是被保留的(即每种类型只有一个实例)。您可以通过id() 函数验证两个包含相同值的整数变量实际上是否指向同一个整数实例。
    • 无论如何,Python 中的一切都是对象。要查看属于整数对象1的函数,可以执行dir(1)
    • 一切都是对象,变量是我们分配给对象的名称(而不是相反!)所以如果你这样做a = b = c = 1; a +=1,那么所有东西都会被分配给对象1,并且然后a 被分配给对象2。对于列表、字典和集合等可变对象,您可以更改对象本身,分配给该对象的所有名称都可以看到该对象,但对于整数、字符串、元组和其他不可变对象,您所能做的就是分配名称到不同的对象。
    • “对象只是引用” 这不是真的。对象就是对象。名称引用它们。
    【解决方案4】:

    正如 danben 之前所说,您只是将同一个 dict 复制到 3 个变量中,因此每个变量都引用同一个对象。

    要获得你想要的行为,你应该在每个变量中实例化一个不同的字典:

    >>> dict_a, dict_b, dict_c = {}, {}, {}
    >>> dict_c['hello'] = 'goodbye'
    >>> print dict_a
    {}
    >>> print dict_b
    {}
    >>> print dict_c
    {'hello': 'goodbye'}
    >>>
    

    【讨论】:

    • 谢谢,当我偶然发现这个主题时,我打算这样做。虽然它不是问题的答案,但非常感谢。
    【解决方案5】:

    您的第一个分配将相同的字典对象分配给变量 dict_a、dict_b 和 dict_c。相当于 dict_c = {}; dict_b = dict_c; dict_a = dict_c。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-29
      • 2014-05-31
      • 2021-01-19
      • 1970-01-01
      • 2018-12-23
      • 1970-01-01
      • 2015-08-29
      相关资源
      最近更新 更多