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} })。有什么问题?
答案 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)
。这不应该是列表的新副本吗?
是的,但是,即使Ab
与A
的列表不同,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有时会使用一种称为“按对象调用”的机制 也称为“按对象引用调用”或“通过共享调用”。
如果我们将函数中的整数,字符串或元组等不可变参数传递给函数,则传递就像call-by-value。
如果我们将列表和字典之类的可变参数传递给函数,它们将通过对象引用传递。
问题的解决方案是使用 deepcopy 。
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)