先说一段废话。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 深拷贝 拷贝对象及其子对象
</div>
先说一段废话。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 深拷贝 拷贝对象及其子对象
</div>