前言: 这个专题主要记录一些在使用python过程中出现的一些自认为理所当然,但是实际情况与想象中差别很大的很神奇的状况,python虽好用,但这个调皮的小孩有时也会对我们开各种小小的玩笑,导致花很多时间去调试、排查错误。故取名为 “python太调皮” 系列。
首先我们看这样一段小程序:
import numpy as np
def test(B):
B[1,2] = 100
return (B)
if __name__ == '__main__':
A = np.array([[1,2,3],[4,5,6],[7,8,9]])
C = test(A)
print("矩阵A:",A)
print("矩阵C:",C)
输出结果如下:
矩阵A:
[[1 2 3]
[4 5 10]]
矩阵C:
[[1 2 3]
[4 5 10]]
数组 C 发生了变化我们很好理解,那么为什么数组 A 也发生了变化呢?其实真相是:python传递容器类参数的时候,类似于C语言,只是传递了这个容器的首个元素的地址,而不是整个元素。在新定义的函数中改变这个值,会导致这个元素发生变化。这种错误同样适用于 python 的 list 数据类型
如果我们不需要原来的数据发生变化,那怎么办呢?
那么就需要用到.copy()
方法,上述函数修改如下:
def test(B):
B = B.copy()
B[1,2] = 100
return (B)
这样,重新运行程序,就可以看到A的值没有被改变了:
矩阵A:
[[1 2 3]
[4 5 6]]
矩阵C:
[[1 2 3]
[4 5 10]]
切忌不能这样使用:
def test(B):
BB = B #这种还是相当于间接把A的首元素地址赋值给了BB,没卵用
BB[1,2] = 100
return (BB)
注:这里涉及到python的深拷贝和浅拷贝的问题,感兴趣的话可以自己搜索。
最后,由于python的事先不需要定义变量类型的特性,我们常常会忽略函数中到底传入的什么类型的值,导致在传入容器类型的值之后不小心改变了原来的值,发生错误。这点在使用python语言的时候一定要特别注意。