先说一段废话。Python中的参数传递都是对象引用传递,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。
Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。
Python提供了3种复制方法,最常见的=、copy.copy()、copy.deepcopy()。下面通过一段代码来看这三种复制方法的异同。
#!/usr/bin/python import copy def fun(list): print(id(list)) for li in list: print id(li), if __name__ == '__main__': a = [x for x in range(5)] a.append({'name':'zhangsan', 'age':20}) print id(a) for x in a: print id(x), print '' print '----------' fun(a) print '' print '----------' fun(copy.copy(a)) print '' print '----------' fun(copy.deepcopy(a)) print ''这里定义了一个列表a,前面的元素的不可变类型的int,在最后append了一个可变类型dict(),然后打印出各个地方列表a和元素的id值。输出结果如下:
打印出了各个对象的ID值,如果id一样,毫无疑问就是同一个对象。当调用默认复制函数时,形参的id和实参的id是相同的(红色框),也就是说的同一个对象,而调用copy模块拷贝时形参id和实参id不同,也就是说是不同的对象。注意观察列表中的最后一个dict元素。默认的=复制和copy复制得到的id是相同的,也就是说他们是同一个对象,而deepcopy的id和其他都不一样,也就是说是新对象。
再看一个代码:
import copy #!/usr/bin/python #encoding=utf-8 a = [1, 2, 3, 4, ['a', 'b']] b = a c = copy.copy(a) d = copy.deepcopy(a) a.append(5) a[4].append('c') print 'a = ', a print 'b = ', b print 'c = ', c print 'd = ', d最后输出
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5] b = [1, 2, 3, 4, ['a', 'b', 'c'], 5] c = [1, 2, 3, 4, ['a', 'b', 'c']] d = [1, 2, 3, 4, ['a', 'b']]所以说copy会对原对象拷贝,但不会递归深拷贝,而deepcopy是递归深拷贝的,这么一来copy是介于=和deepcopy的,用的肯定不多。
1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。
2. copy.deepcopy 深拷贝 拷贝对象及其子对象