函数的参数传递
函数参数传递有两种方式,传值和传引用,传值只是把变量的值复制一份给了实参,函数内部的操作不会改变函数外部变量的值,而传引用传递的是外部变量的地址,函数内部直接操作函数外部变量的储存空间,在调用函数之后,函数外部变量的值一般会改变
def Demo(a):a = a + 1print(id(a))if __name__ == '__main__':a = 3print(id(a)) # 140705335465056Demo(a) # 140705335465088print(id(a)) # 140705335465056
看到变量a在函数调用前后地址值没有改变,证明在传递数值时传递的是变量的值,字符等类型也一样,然后尝试列表,元组
def Demo(a):a.append(3)print(id(a))if __name__ == '__main__':s = [1,2]print("value = " + str(s) + "address = " + str(id(s))) # value = [1, 2]address = 1574898786888Demo(s) # value = [1, 2, 3]address = 1574898786888print("value = " + str(s) + "address = " + str(id(s))) # value = [1, 2, 3]address = 1574898786888
函数调用前后地址值一致,证明传递的是引用,并且函数执行以后a的值也发生了改变,说明a.append()
是在s的内存中操作的
如果传递的是元组,应为元组不可修改,所以三次输出的都是同一块地址,但其实以元组为参数传递时传递的是值。
还有一种情况
def Demo(a):a[0].append(3)print("value = " + str(a) + "address = " + str(id(a)))if __name__ == '__main__':a = ([1,2], 2)print("value = " + str(a) + "address = " + str(id(a))) # value = ([1, 2], 2)address = 2616967970056Demo(a) # value = ([1, 2, 3], 2)address = 2616967970056print("value = " + str(a) + "address = " + str(id(a))) # value = ([1, 2, 3], 2)address = 2616967970056
如果元组中的元素是列表,在调用函数前后,函数外部的a也发生了变化,根据刚开始说的,这感觉是在传引用,但其实不是,对于函数外部的a来说,他的第0个元素始终是<class 'list'>
,至于列表中元素有没有发生变化,元组并不关心,元组判断元素有没有改变判断的是元素的地址有没有改变,而调用append()函数时,传递的是可变元素列表,地址值不会发生改变,这也就是为什么元组不可变,但如果元组中的数据是可变类型的话该数据就可变的原因
总结
python有两种数据类型,可变和不可变数据,对于可变数据类型,诸如列表,字典,集合在函数传参时传引用,对于不可变数据类型,如数值,字符,元组,在函数传参时传值,但更准确的来说,python函数传参时使用传对象引用的方式,如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值’来传递对象。
最后还是要注意像元组中数据是可变类型的情况
参考链接1
参考链接2