功能修改列表

时间:2018-03-20 22:55:41

标签: python list function reference

def make_Ab(A,b):
    n = len(A)
    Ab = list(A)
    for index in range(0,n):
        Ab[index].append(b[index][0])
    print(A)
    return Ab.copy()

A = [[0.0, 1.0, 1.0, 2.0], [1.0, 3.0, 1.0, 5.0], [2.0, 0.0, 2.0, 4.0]]

b = [[1],[2],[3]]

print(A)

[[0.0, 1.0, 1.0, 2.0], [1.0, 3.0, 1.0, 5.0], [2.0, 0.0, 2.0, 4.0]]

Ab = make_Ab(A,b)
print(A)

[[0.0, 1.0, 1.0, 2.0, 1], [1.0, 3.0, 1.0, 5.0, 2], [2.0, 0.0, 2.0, 4.0, 3]]

我不知道为什么我的功能会修改我的原始列表。我没有将A指定为函数中的全局(我甚至试图在不同的函数中声明它,因此它不会是全局的),我没有通过引用传递它(如{{1} })。有什么问题?

2 个答案:

答案 0 :(得分:3)

这里的问题是,虽然你没有修改变量(你不能没有global),但你 修改了

起初这可能有点令人困惑。这两个看起来像他们做同样的事情:

>>> a = [1, 2, 3]
>>> a = a + [1]
>>> a
[1, 2, 3, 1]
>>> a = [1, 2, 3]
>>> a.append(1)
>>> a
[1, 2, 3, 1]

但他们不是。第一个是从a[1]创建新列表,然后将新列表绑定回名称a。如果对该列表有其他参考,则不会改变。另一方面,第二个是更改a命名的实际列表对象。如果对该列表有其他引用,则会发生变化。

>>> a = [1, 2, 3]
>>> b = a
>>> a = a + [1]
>>> b
[1, 2, 3]
>>> a = [1, 2, 3]
>>> b = a
>>> a.append(1)
>>> b
[1, 2, 3, 1]

您在代码中执行的操作是第二个,更改列表对象的值。这意味着对该列表对象的每个引用,即使是您无权访问的名称,也会看到更改。

但您不是在修改A本身,而是在修改list(A)。这不应该是列表的新副本吗?

是的,但是,即使AbA的列表不同,Ab[0]仍然是与A[0]相同的列表。您创建了一个新列表,引用与原始列表相同的子列表。所以当你改变那些子列表时......同样的问题。

如果您想更改此功能,可以执行以下两项操作之一:

  • 复制函数顶部的所有子列表以及列表,这样就可以改变副本而不是原始副本。
  • 不要在列表中使用任何变异操作;建立一个新的。

第一个是简单的更改:代替Ab = list(A),执行Ab = copy.deepcopy(A)Ab = [list(sub) for sub in Ab]

第二个需要重写代码:

def make_Ab(A,b):
    n = len(A)
    Ab = []        
    for index in range(0,n):
        Ab.append(A[n] + [b[index][0]])
    return Ab

(或者,当然,您可以将其重写为列表理解。)

答案 1 :(得分:0)

将参数传递给函数 - Python

  

Python有时会使用一种称为“按对象调用”的机制   也称为“按对象引用调用”或“通过共享调用”。

按值调用 - 不可变参数

如果我们将函数中的整数,字符串或元组等不可变参数传递给函数,则传递就像call-by-value。

按对象调用或按对象引用调用 - 可变参数

如果我们将列表和字典之类的可变参数传递给函数,它们将通过对象引用传递。

解决方案

问题的解决方案是使用 deepcopy

  1. 从复制导入深度复制
  2. 添加
  3. Ab = list(A) 替换为 Ab = deepcopy(A)
  4. 返回Ab.copy() 替换为 return Ab
  5. main.py

    from copy import deepcopy
    
    
    def make_Ab(A, b):
        n = len(A)
        Ab = deepcopy(A)
        print("\nmake_Ab-before append: \n    A=", A)
        for index in range(0, n):
            Ab[index].append(b[index][0])
        print("\nmake_Ab-after append: \n    A=", A)
        return Ab
    
    A = [[0.0, 1.0, 1.0, 2.0], [1.0, 3.0, 1.0, 5.0], [2.0, 0.0, 2.0, 4.0]]
    
    b = [[1], [2], [3]]
    
    print("Before: make_Ab call, \n    A=", A)
    
    Ab = make_Ab(A, b)
    
    print("\nAfter: make_Ab call, \n    A=", A)
    print("\nAfter: make_Ab call, \n    Ab=", Ab)
    

    输出

    enter image description here