Python中的对象(四)
1、复制对象
-
>>> LIST1 = [1, 2, 3]
-
>>> LIST2 = LIST1[:] # 列表的切片(slicing)功能
-
>>> id(LIST1), id(LIST2)
-
(4293721356L, 4293727372L)
-
>>> LIST1[0] = 0
-
>>> LIST1
-
[0, 2, 3]
-
>>> LIST2
- [1, 2, 3]
对象有不同的identity,即它们分别放在了不同内存地址里。所以LIST1和LIST2指向的是两个不同的的对象,只是此刻它们的值
是一样的。当我们改变其中一个的值时,另一个对象不会受到影响, 即不会随着改变 【1】 。过程如图1所示。

图 1. 隐式复制
从图中我们可以看出,当执行LIST1[0] = 0时,只是使LIST1的第一个元素指向0,LIST2的元素的绑定(引用)并没有变。我们之
所以称它为隐式复制,是因为列表切片(slicing)操作复制了一个同值的对象。
b. 显示复制
我们也可以用Python的标准库的copy模块来复制一个对象。它有两种方法,一种是浅拷贝(shallow copy),一种是深拷贝(deep
-
import copy
-
-
x = copy.copy(y) # make a shallow copy of y
- x = copy.deepcopy(y) # make a deep copy of y
是一样的,且不会真正的复制对象。
-
>>> a = 1
-
>>> b = copy.copy(a)
-
>>> b
-
1
-
>>> id(a), id(b)
-
(31284744L, 31284744L)
>>> c = copy.deepcopy(a) -
>>> c
1
>>> id(a), id(b), id(c)
(31284744L, 31284744L, 31284744L)
下面的例子解释了两种方法的不同。
b.1. 浅拷贝(shallow copy)
-
>>> L1 = [[1,2], ['a', 'b']]
-
>>> L2 = copy.copy(L1)
-
>>> id(L1), id(L2)
-
(39824136L, 39847240L) # L1和L2分别指向两个不同的对象
-
>>> L1
-
[[1, 2], ['a', 'b']]
-
>>> L2
-
[[1, 2], ['a', 'b']] # L2和L2的值是一样的,因为我们复制了对象。
-
>>> L2[0][0] = 0 # 改变L2指向的第一个对象的第一个元素的值。
-
>>> L1
-
[[0, 2], ['a', 'b']]
-
>>> L2
-
[[0, 2], ['a', 'b']] # L1和L2指向的对象的值同时都改变了。

图 2. Shallow Copy
从图中可以看出,shallow copy只是复制被拷贝对象的第一级(top level)对象。所以,对于第二级对象仍然是引用的关系。因此,
当我们改变第二级对象的值时,两个对象的值都会同时改变。
b2. 深拷贝(deep copy)
-
>>> import copy
-
>>> L1 = [[1, 2], ['a', 'b']]
-
>>> L2 = copy.deepcopy(L1)
-
>>> id(L1), id(L2)
-
(40001608L, 40004488L) # L1和L2分别指向两个不同的对象
-
>>> L1
-
[[1, 2], ['a', 'b']]
-
>>> L2
-
[[1, 2], ['a', 'b']] # L2和L2的值是一样的,因为我们复制了对象。
-
>>> L1[0][0] = 0 # 改变L1指向的第一个对象的第一个元素的值。
-
>>> L1
-
[[0, 2], ['a', 'b']]
-
>>> L2
-
[[1, 2], ['a', 'b']] # L2指向的对象的值并没有变化。
的过程如图3所示:

图 3. Deep Copy
从图中可以看出,整个对象的结构被复制了,其实就是递归复制。
至此,Shallow Copy和Deep Copy的区别已经变得很清楚了。在实际的开发项目中,我们应该根据需要来选择对象复制的方法。
2、比较对象
在实际应用中,我们有时候需要比较两个对象。Python中比较两个对象涉及到两种方式: “==” 和 “is”。“==”比较是测试两个被引用的对象的值是否相等。 看下面的代码块1,
代码块1
-
>>> L1 = [1, 2, 3]
-
>>> L2 = [1, 2, 3]
-
>>> id(L1), id(L2)
-
(40080968L, 40082824L)
-
>>> L1 == L2
-
True
>>> L1 is L2
False -
>>>
“is” 比较是测试两个对象是否是同一个对象。看下面的代码块2,
代码块2
-
>>> L1 = [1, 2, 3]
-
>>> L2 = L1
-
>>> id(L1), id(L2)
-
(40082824L, 40082824L)
-
>>> L2 is L1
- True
-
>>> L2 == L1
True
- >>>
实际上,“is”比较的是两个对象的identity(通过id()获取的一个整数值),如果identity相等则为True,否则则为False。
实际上在Python中,如果identity相等,必然是同一个对象。所以,在代码块2中“L1 is L2”的结果是True,在代码块1中
”L1 is L2“的结果是False。而 ”==“比较的仅仅是对象的值。同一个对象,值必然相等,不同对象,它们的值有可能相等,
有可能不相等。也就是说
如果”a is b"是True,那么“a == b”必定为True;
如果”a is b"是False,那么“a == b“可能为True或者False。
所以,我们可以把”==“看做是弱比较,把”is“看做是强比较。
由于Python不会重复创建非复合对象,一旦一个非复合对象被创建,它将会被引用数次,直到被垃圾回收掉。我们可以
用sys.getrefcount()来获得所给对象被引用的次数。
-
>>> import sys
-
>>> sys.getrefcount(True)
-
31
-
>>> sys.getrefcount(0)
-
172
- >>>
已经远远超越了脚本语言的范畴。Python已经渗透到了软件开发的各个领域,并且越来越流行,越来越火了。学习Python,
使用Python,享受Python吧!
注:
【1】 前提是对象的值是非复合对象,如果是复合对象,其实也是Shallow Copy。
【2】 可以包含其他对象的对象叫复合对象。例如: 列表,字典,类实例等。
by Harrison Feng in Python