Python传值与传址问题
问题:在Python中参数是如何传递的?
先说结论:
python参数传递方式:传递对象引用(传值与传址的混合方式)
不可变对象(数字,字符串,元组):传值
可变对象(字典,列表):传址
1.传值和传址的区别
传值就是传入一个参数的值,函数里面如果对传入参数重新赋值,函数的全局变量不会跟着改变
传址就是传入一个参数的地址,函数里面如果对传入参数重新赋值,函数的全局变量也会跟着作出相应改变
示例:
值传递:
def foo(arg):arg = 2print(arg)a = 1foo(a) # 输出:2print(a) # 输出:1
传址:
def bar(args):args.append(1)b = []print(b)# 输出:[]print(id(b)) # 输出:4324106952bar(b)print(b) # 输出:[1]print(id(b)) # 输出:4324106952
分析:
Python函数中,参数传递本质上是一种赋值操作,而赋值操作是名字到对象的一个绑定过程
代码片段一:

a绑定了1,调用foo函数后,arg赋值1,当arg执行重新赋值为2之后,相当于将1上的arg标签撕掉,贴到了2身上,并不影响a。因此print(a)的结果还是1。
代码片段二:

一开始b绑定空列表,调用函数时参数arg也绑定该空列表,当函数执行到append时,并没有重新赋值操作,append方法只是对列表插入一个元素,因为b与arg都是绑定在同一个对象上,因此b的内容在调用函数后也发生了变化。
2.copy与deepcopy
如果我们不想修改原始列表的内容怎么办呢?这时候就要用到copy函数了
代码:
a = [1, 2, 3, 4, 5]b = a.copy()print(a)b[2] = 66print(a)print(b)print(id(a))print(id(b))#输出[1, 2, 3, 4, 5][1, 2, 3, 4, 5][1, 2, 66, 4, 5]45078213764507821376
这里用了copy让b与a相等,后面修改了b的值,并不影响a的值
但是copy只是浅拷贝,只拷贝一层的内容,对于嵌套列表的情况并不能很好的实现我们的需求,比如下面这种情况
a = [1, [1, 2], 3]b = a.copy()a[1].append(4)print(a)print(b)# 输出[1, [1, 2, 4], 3][1, [1, 2, 4], 3]
可以看到b的值也跟着一起改变了,这种结果显然不是我们想要的
我们想完全复制列表,让新列表与原列表完全没有关系,这就需要用到我们的deepcopy,深拷贝
a = [1, [1, 2], 3]b = copy.deepcopy(a)a[1].append(4)print(a)print(b)# 输出[1, [1, 2, 4], 3][1, [1, 2], 3]
3.总结:
python参数传递方式:传递对象引用(传值与传址的混合方式)
不可变对象(数字,字符串,元组):传值
可变对象(字典,列表):传址
它们两者的区别:
传值就是传入一个参数的值,
传址就是传入一个参数的地址,也就是内存地址。
函数中对传入对象重新赋值,传值参数是不会改变的,用传址传入就会改变。
可以分情况使用copy与deepcopy避免修改原始对象。
以上!
博客地址:www.tangxuansite.com
