今天面试被问了一个问题:python函数传参是传值还是传递引用?
虽然我知道是传递引用,但是不能深入理解,所以回来就做了一些测试加深理解。
1. 当参数是不可变对象时
def test(b): print("对参数b进行操作前") print("参数的id:",id(b)) b += 2 print("对参数b进行操作后") print("参数的id:",id(b)) return b a = 2 print("传入参数前") print("a的id:",id(a)) n = test(a) print() print("传入参数运行test函数后") print("a的值:",a) print("a的id:",id(a)) print("n的id:",id(n))
传入参数前 a的id: 1683941872 对参数b进行操作前 参数的id: 1683941872 对参数b进行操作后 参数的id: 1683941936 传入参数运行test函数后 a的值: 2 a的id: 1683941872 n的id: 1683941936
可以看出,参数传递到test()函数中,一开始,b和a的id是一样的,当对b进行更改后,b的id发生变化。将b返回给n,n的id和b一样。但是test()函数运行完之后,a的引用并没有发生变化。
数值2和4在内存中的地址是不变的,这两个也是不可变对象(即改变了它就要改变地址)。当执行a = 2时,a就指向了对象2的地址,把a作为参数传递给test()函数后,b也就指向了对象2的地址。执行b += 2之后,b = 4,次数b就指向了对象4的地址。所以test()运行完毕后,a仍然指向对象2的地址,并没有发生变化。
2. 当参数是可变对象时,如列表。
def test(b): print("对参数b进行操作前") print("参数的id:",id(b)) b *= 2 print("对参数b进行操作后") print("参数的id:",id(b)) return b a = [1,2,3] print("传入参数前") print("a的id:",id(a)) n = test(a) print() print("传入参数运行test函数后") print("a的值:",a) print("a的id:",id(a)) print("n的id:",id(n))
传入参数前 a的id: 2291610353160 对参数b进行操作前 参数的id: 2291610353160 对参数b进行操作后 参数的id: 2291610353160 传入参数运行test函数后 a的值: [1, 2, 3, 1, 2, 3] a的id: 2291610353160 n的id: 2291610353160
自始至终a和b的id都没有发生变化,这是因为列表是可变对象,当创建了列表a = [1,2,3]之后,就给它分配了一个内存,不管对这个列表进行什么计算,列表的内存地址都不发生变化。要想使a的id发生变化,可赋值一个不同的对象。
将一个set对象赋值给a,a的id肯定会发生变化,但是将另一个[1,2,3]列表赋值给a时,a的id也发生了变化。这说明两个列表虽然内部元素一样,但是是不同的对象。要注意可变对象和不可变对象之间的区别。