Python传值与传址问题
问题:在Python中参数是如何传递的?
先说结论:
python参数传递方式:传递对象引用(传值与传址的混合方式)
不可变对象(数字,字符串,元组):传值
可变对象(字典,列表):传址
1.传值和传址的区别
传值就是传入一个参数的值,函数里面如果对传入参数重新赋值,函数的全局变量不会跟着改变
传址就是传入一个参数的地址,函数里面如果对传入参数重新赋值,函数的全局变量也会跟着作出相应改变
示例:
值传递:
def foo(arg):
arg = 2
print(arg)
a = 1
foo(a) # 输出:2
print(a) # 输出:1
传址:
def bar(args):
args.append(1)
b = []
print(b)# 输出:[]
print(id(b)) # 输出:4324106952
bar(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] = 66
print(a)
print(b)
print(id(a))
print(id(b))
#输出
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 66, 4, 5]
4507821376
4507821376
这里用了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