Python传值与传址问题

smile唐

共 1448字,需浏览 3分钟

 · 2022-05-14

问题:在Python中参数是如何传递的?

先说结论:

python参数传递方式:传递对象引用(传值与传址的混合方式)

不可变对象(数字,字符串,元组):传值

可变对象(字典,列表):传址



1.传值和传址的区别

传值就是传入一个参数的值,函数里面如果对传入参数重新赋值,函数的全局变量不会跟着改变

传址就是传入一个参数的地址,函数里面如果对传入参数重新赋值,函数的全局变量也会跟着作出相应改变



示例:

值传递:

def foo(arg):    arg = 2    print(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函数中,参数传递本质上是一种赋值操作,而赋值操作是名字到对象的一个绑定过程

  • 代码片段一:

de59388cc2033a25b9613c150130c892.webp

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


  • 代码片段二:


cb2450629dbf0b725d3162dc121b5a4c.webp


一开始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]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




浏览 94
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报