Python的变量指向和引用问题、赋值和拷贝问题

参考博客

引言

python里的变量对象包括不可变对象(int,float,long,str,tuple等),和可变对象(list,set,dict等)。对于这两种对象的赋值和拷贝问题是和其它语言有差别的,不加分辨地使用容易出错。

浅复制问题

不可变对象(int,float,long,str,tuple等)其实是标签,类似于c语言里的指针。例如对于int类型的对象a,a=10是把a贴到10这个数上了,而a=20是把a从10上撕下来,拿去贴到20上面了。因此a=10后执行a=20,a地址会变

a = 10
print(id(a))
a = 20
print(id(a))

结果如下,地址值可能会不一样,看你的python解释器的分配情况,我们只要比较前后地址值的改变与否即可,下同。

140725279137824
140725279138144

并且,除了a=a这个情况,a的地址不会变,哪怕是a=10.0(float型),a=2a-a,这么处理之后的a地址也会变(不过当a是int的时候,a=2a-a地址不变,但是a=0.5a+0.5a地址会变,因此猜测是解释器的优化原因)

a = 10.0
print(id(a))
a = 0.5*a+0.5*a
print(id(a))

结果

2159059426256
2159059426320

这种直接用等于号赋值只是贴标签,叫做浅复制,就是不是把a的值拷贝到b,而是让a和b都指向同一个值,这样子会出现一些问题。例如在列表赋值时,values并没有出现[0,[0,1,2],2]这种情况,而是出现了循环嵌套。这是因为values[1]的标签贴到了原来的values上,于是在检索values[1]的时候就跳到values[0],接着往下走values[1],然后继续循环。

values = [0, 1, 2]
print(id(values))
values[1] = values
print(id(values))
print(values)

结果

2579107863680
2579107863680
[0, [...], 2]

而直接用values[:]貌似可以解决这个问题

values = [0, 1, 2]
print(id(values))
values[1] = values[:]
print(id(values))
print(values)

结果

2366984019008
2366984019008
[0, [0, 1, 2], 2]

但是values[:]只是复制顶层,如果出现数组嵌套就还是会出现错误情况,可见于
这篇博客
还有一点需要注意的是,a=a+a和a+=a是不一样的,后者是原地复操作。例如对于列表,就是在它之后继续加元素,但是列表头的地址不变

a = [10];
print(id(a))
a = a+a;
print(id(a))
print(a)
b = [10];
print(id(b))
b += b;
print(id(b))
print(b)

结果

1716028562560
1716033074112
[10, 10]
1716033074240
1716033074240
[10, 10]

但是对于int等变量的值,原地操作仍然会改变地址值。这还是因为贴标签的原因。python存了个10,然后把a贴上去,但是a+a=20,所以python开了个存储空间放20,把a标签撕下来贴到20上面了。这时候再b=10,就是把b贴到10上,因此这时b的地址和最开始a的地址是一样的。

a = 10;
print(id(a))
a = a+a;
print(id(a))
print(a)
b = 10;
print(id(b))
b += b;
print(id(b))
print(b)

结果

140725279137824
140725279138144
20
140725279137824
140725279138144
20

深复制问题

深复制可以用copy 模块的 deepcopy 方法,具体可以看[这个](copy 模块的 deepcopy 方法)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值