Python for循环中的引用传递和值传递

先上代码:

a = [[1],[2],[3]]
b = [[4,5],[6,7],[7,8]]
for i,j in zip(a,b):
    print(i,j)
    i = [9]
    #i[0] = 8
    j[:2]=[1,2]
    print(i, j)
print(a)
print(b)

运行的结果:

[1] [4, 5]
[9] [1, 2]
[2] [6, 7]
[9] [1, 2]
[3] [7, 8]
[9] [1, 2]
[[1], [2], [3]]
[[1, 2], [1, 2], [1, 2]]

可以看到修改i的值不会造成数组a的值的修改,而修改j的值会造成数组b的值的修改,这是为什么呢?

引用传递和值传递

引用传递(Pass by Reference)

在引用传递中,函数接收的是变量的地址,也就是对象的引用。
当你把一个可变对象(如列表、字典等)传递给函数时,函数内部对该对象的修改会影响到原始的对象。
这是因为函数接收的是对象的引用,而不是对象的副本。
示例:

  def modify_list(lst):
      lst[0] = 'changed'

  my_list = [1, 2, 3]
  modify_list(my_list)
  print(my_list)  # 输出 ['changed', 2, 3]

值传递(Pass by Value)

在值传递中,函数接收的是变量的值的副本。
当你把一个不可变对象(如整数、字符串等)传递给函数时,函数内部对该变量的修改不会影响到原始的变量。
这是因为函数接收的是变量的值的副本,而不是变量本身。
示例:

  def modify_int(x):
      x = 'changed'

  my_int = 10
  modify_int(my_int)
  print(my_int)  # 输出 10

总的来说,在 Python 中,变量的赋值行为遵循以下规则:
对于可变对象,变量存储的是对象的引用,即引用传递。
对于不可变对象,变量存储的是对象的值,即值传递。

对一开始的问题做出简化

a = [[1],[2],[3]]
b = [[4,5],[6,7],[7,8]]
c = a
c[0]=[8]
print(a)

这个c按理说是a的一个副本,但是为什么对c修改会对a造成影响呢?

当我们执行 c = a时,c 并不是 a 的副本,而是指向了 a 中同样的列表对象。也就是说,a 和 c 指向的是同一块内存地址。

然后当我们执行 c[0] = [8] 时,我们是在修改 c 指向的那个列表的第一个元素。但是由于 a 和 c 指向的是同一个列表对象,所以这个修改同时也影响到了 a。

这就是为什么打印 a 的结果会变成 [[8], [2], [3]]。

如果你想创建 a的副本,而不是让 c 指向同一个列表对象,可以使用以下方式:

a = [[1], [2], [3]]
b = [[4, 5], [6, 7], [7, 8]]
c = a[:]  # 或者 c=copy.copy(a) 或 c = copy.deepcopy(a)
c[0] = [8]
print(a)  # 输出 [[1], [2], [3]]
print(c)  # 输出 [[8], [2], [3]]

在最开始的问题中

a = [[1],[2],[3]]
b = [[4,5],[6,7],[7,8]]
for i,j in zip(a,b):
    print(i,j)
    i = [9]            #这个是值传递
    #i[0] = 8          #这个是引用传递  
    j[:2]=[1,2]        #这个是引用传递
    print(i, j)
print(a)
print(b)