when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.
写 python 的过程中,拷贝总是少不了的,遥记得 C++ 里有个东西叫深拷贝(总之涉及到指针就变得啥都不好理解了),同为面向对象,但是 python 不是没有指针吗?
这还得从 python 的变量开始说起
在 Python 中,一个变量可以说是内存中的一个对象的「标签」,它绑定到内存中的对象。准确地说,变量不是引用另一个变量,而是绑定到某个对象
一般情况下,当一个对象不再能通过程序中的任何方式访问时,它就可能被垃圾回收机制回收。不过,像小整数、短字符串这类对象,Python 可能会缓存复用,不一定会立即释放。
1 | a = 2 # 现在变量 a 绑定到内存中的一个 int 型对象(a 相当于 2 的名字) |
综上,变量不需要类型,类型是属于对象的,这也是 Python 中的变量可以被任何类型赋值的原因
Python 使用对象模型来储存数据,任何类型的值都是一个对象
所有的 Python 对象都有 3 个特征:
id() 来得到它。这个值可以被认为是该对象的内存地址type() 来查看 python 对象的类型1 | a = 1 |
Python 3 中有 6 种标准的数据类型:Numbers、Strings、List、Tuple、Sets、Dictionaries,其中 Numbers、Strings 和 Tuple 是不可更改的对象,而 List、Dictionaries、Sets 是可以修改的对象,那么可变与不可变有什么区别呢?
这里需要先区分两个概念(根据 id() 是否还一样):
a = 5、a = [1, 2]a.append(7)、a[0] = 100只有当多个变量指向同一个可变对象,并且其中一个变量对这个对象做了原地修改时,其他变量才会看到变化
1 | x = 1 # x 绑定到内存中值为 1 的对象 |
1 | x = [1, 2] # x 绑定到一个 list 类型的对象 |
再看一个容易混淆的例子:
1 | a = [1, 2, 3] |
注意,+= 是否原地修改取决于对象类型。对于字符串、整数、元组这类不可变对象,+= 不能原地修改,只能创建新对象再重新绑定
1 | a = "abc" |
在深拷贝之前,得先知道什么是浅拷贝
浅拷贝是指创建一个新的对象,其内容是原对象中元素的引用(拷贝组合对象,不递归拷贝子对象)
常见的浅拷贝有:切片操作、工厂函数、对象的 copy() 方法、copy 模块中的 copy 函数
1 | a = [1, 2, 3] |
深拷贝是指创建一个新的对象,然后递归地拷贝原对象所包含的子对象
1 | a = [1, 2, 3] |
为什么使用了深拷贝,a 和 c 中元素的 id 还是一样呢?
因为对于不可变对象,当需要一个新的对象时,Python 可能不会真的创建一个全新的对象,而是复用已经存在的、类型和值都一致的对象。这个机制不会影响 a 和 c 的相互独立性,因为不可变对象不能被原地修改。即使两个列表中的元素是同一个不可变对象,也不会出现“修改其中一个列表的元素对象,另一个列表跟着变”的问题。
1 | import copy |
此时,对于可变对象而言,浅拷贝带来的潜在隐患就一目了然了
be yourself, everyone else is already taken.