Python引用、对象、拷贝的理解

        由于Python的动态特性,Python中变量和对象是分离的,在使用变量的时候,只需要直接赋值即可(在给变量赋值前不需要声明,C/C++等静态语言需要声明),而在Python中,一切皆对象,所以变量的本质是对对象的引用。

例子 一

a = 1

实质上是a指向了对象1,可以用命令行模式id()来查看对象的身份

                         

例子二:

a = 1

a = "apple"     

               

a变量先引用了对象1,再引用了对象apple,可以看到,a不再指向对象1,而对象1会被Python的内存机制当作垃圾回收处理掉。

例子三:

a =2

b = 2

按照例一的说法,应该是这样,a,b分别引用了两个对象(只不过都是为2)

用函数查看变量a和b的引用情况:

发现,a和b指向了同一地址,也就是指向了同一对象。这个跟python的内存机制有关系,因为对于语言来说,频繁的进行对象的销毁和建立,特别浪费性能。所以在Python中,整数和短小的字符,Python都会缓存这些对象,以便重复使用。

所以实际上是这样:

相当于你今天穿着a牌子的衣服,明天穿着b牌子的衣服,你说你再也不是自己了,是不是有点2?

例子四:

a = 3

b = a(即让变量b指向对象a,但a也是指向另一个对象,即b指向对象a指向的对象)

a = a + 2

可以看到 a 的引用改变了,但是 b 的引用未发生改变;a,b指向不同的对象; 第3句对 a 进行了重新赋值,让它指向了新的 对象了;即使是多个引用指向同一个对象,如果一个引用值发生变化,那么实际上是让这个引用指向一个新的引用,并不影响其他的引用的指向。从效果上看,就是各个引用各自独立,互不影响。

例子五:

L1 = [1,2,3]

L2 = L1

L1和L2引用一样,指向了同一列表对象。赋值即引用。接下来,我们操作

L1[0] = 5

L1 和 L2 的引用没有发生任何变化,但是 列表对象[1,2,3] 的值 变成了 [5,2,3](列表对象改变了)

在该情况下,我们不再对L1这一引用赋值,而是对L1所指向的表的元素赋值。结果是,L2也同时发生变化。

        原因何在呢?因为L1,L2的指向没有发生变化,依然指向那个表。表实际上是包含了多个引用的对象(每个引用是一个元素,比如L1[0],L1[1]..., 每个引用指向一个对象,比如1,2,3), 。而L1[0] = 5这一赋值操作,并不是改变L1的指向,而是对L1[0], 也就是表对象的一部份(一个元素),进行操作,所以所有指向该对象的引用都受到影响。

(与之形成对比的是,我们之前的赋值操作都没有对对象自身发生作用,只是改变引用指向。)

        列表可以通过引用其元素,改变对象自身(in-place change)。这种对象类型,称为可变数据对象(mutable object),词典也是这样的数据类型。而像之前的数字和字符串,不能改变对象本身,只能改变引用的指向,称为不可变数据对象(immutable object)。

检查两个对象是否指向同一对象,可用关键字 is判断

 

例子六:引用对象的类型与拷贝

a = [1,2,3,[4,5]]

浅拷贝:c = copy.copy(a)

说明c 和a 指向了不同的对象,但是两个数值一样的(跟例三的对比)

深拷贝:d = copy.deepcopy(a)

显然d 也是指向了与a不同的对象,这两个对象也是一样的。

总结,赋值是指向同一个对象(即引用对象本身),拷贝是创建了新的对象(新对象包含的对象和原来的一样)

那么,c 和 d 是什么关系,会不会相等?(一个浅一个深,肯定有区别)

现在来解释背后的原理

1.对于浅拷贝:copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。(比深拷贝更加节省内存)

2. copy.deepcopy 深拷贝 拷贝对象及其子对象

故对于浅拷贝,a在对父对象做改变的时候,c不会有变化,因为是两个对象,但对子对象,也就是上面的【4,5】改变,由于a和c引用的是同一对象,故两者都改变。

而对于深拷贝,由于两者属于独立的,d不会随着a的改变而改变。

例如:

在a对象的后面添加"test",即父对象改变

可以看到,c 和 d都没有变化

如果对子对象【4,5】做改变的话呢?

注意到子对象属于父对象的一个元素(a[3])

a[3].append("Python")

可以看到,对子对象的改变,c也改变了,d依然保持不变。

 

参考博客:

https://www.cnblogs.com/ShaunChen/p/5656971.html

https://www.cnblogs.com/alan-babyblog/p/5177597.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值