【问题标题】:Why is python treating lists like this when defining a function?为什么python在定义函数时会这样处理列表?
【发布时间】:2018-05-31 21:39:22
【问题描述】:

我正在编写代码,变量开始表现得很奇怪,并被分配给我认为它们不应该分配的东西。因此,我决定将情况降低到最小的复杂性以解决我的疑问,这就是发生的事情:

以下代码:

a = [2]

def changeA(c):
    d = c
    d[0] = 10
    return True

changeA(a)

print(a)

打印“[10]”。这对我来说没有意义,因为我从未在第一次分配之后将列表“a”分配为任何内容。在函数 changeA 内部,局部变量 d 被赋值为函数的输入,在我看来,这种赋值是双向发生的,甚至改变了“外部”。如果是这样,为什么?如果不是,为什么会这样?

我也注意到代码

a = [2]

def changeA(c):
    d = list(c)
    d[0] = 10
    return True

changeA(a)

print(a)

表现正常(即,如我所料)。

编辑:这个问题被认为与this one 重复。我不认为这是真的,因为这里违反了函数内部过程的局部性特征也很重要。

【问题讨论】:

标签: python python-3.x list variables


【解决方案1】:

Python 变量是对对象的引用,有些对象是可变的。数字不是,字符串和元组也不是,但列表、集合和字典是。

让我们看看下面的 Python 代码

a = [2]       # ok a is a reference to a mutable list
b = a         # b is a reference to the exact same list
b[0] = 12     # changes the value of first element of the unique list
print(a)      # will display [12]

【讨论】:

    【解决方案2】:

    在第一个示例中,您只需将c(即a)的引用传递给d

    所以无论你对d 做什么,都会在a 上发生。

    在第二个示例中,您复制c(即a)的值并将其赋予新变量d

    所以d 现在与c(即a)具有相同的值,但引用不同。

    注意:您可以使用id() 函数查看变量的引用或ID。

    a = [2]
    print id(a)
    
    def changeA(c):
        d = c
        pirnt id(d)
        d[0] = 10
        return True
    
    changeA(a)
    
    print(a)
    
    
    a = [2]
    print id(a)
    def changeA(c):
        d = list(c)
        print id(d)
        d[0] = 10
        return True
    
    changeA(a)
    
    print(a)
    

    【讨论】:

      【解决方案3】:

      因为当你这样做时:

       d = list(c)
      

      创建一个新对象。但是当你这样做时

      d = c
      

      您正在引用该对象。

      如果你这样做了

      d.append(5)
      

      你会得到第一个例子

      [10,5]
      

      与第二个操作相同,列表未修改。

      以下链接中的更深入解释:http://henry.precheur.org/python/copy_list

      【讨论】:

        【解决方案4】:

        在 Python 中,名称指的是值,因此您有 2 个名称指向同一个值。

        【讨论】:

          【解决方案5】:

          在版本 1 中,您创建一个列表 a,将其传递给化名 c 下的函数,为相同的列表创建 另一个 化名 d,然后更改该列表中的第一个值。 acd 都指向同一个列表。

          在版本 2 中,您使用的是 list(c),对于 Python,这意味着“获取名为 c 的可迭代事物的内容,并从中创建一个新的、不同的列表,名为 d”。现在,您的列表有 两个 副本浮动。一种称为ac,另一种称为d。因此,当您更新d[0] 时,您正在操作列表的第二个副本。 a 保持不变。

          【讨论】:

            【解决方案6】:

            'd=c' 表示如前所述的参考副本。这意味着,现在 d 将引用与 c 相同的对象。当您对引用的对象进行直接操作时,a 所引用的对象的值也会发生变化。

            当您执行 'd = list(c)' 时,这意味着创建了一个新的列表对象,其中包含 c 的烘焙。但是, d 不再引用与 a 相同的对象。因此,函数内的更改不会影响 a。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-12-21
              • 2019-06-01
              • 2021-12-22
              • 1970-01-01
              • 1970-01-01
              • 2019-04-07
              • 2017-02-26
              相关资源
              最近更新 更多