Python编程学习——拷贝


简介:
这一篇博客主要讨论Python对象的拷贝问题,区分浅拷贝和深拷。为了保持追踪内存中的对象,Python使用了引用计数这一简单技术,下面将进行简单介绍。

1、引用计数:
当对象被创建并赋值给变量时,该对象的引用计数就被设置为 1 。当同一个对象又被赋值给其他变量时,或作为参数传给函数、方法或类实例时,或被赋值为一个窗口对象的成员时,该对象的一个新的引用(或称为别名)就被创建,该对象的引用计数加 1 。使用del关键字可以减少引用计数。
我们可以看到下面代码:

#!/usr/bin/env python
import sys
x = 3.14
print 'x ', id(x), sys.getrefcount(x)
y = x
print 'y ', id(y), sys.getrefcount(y)
z = 3.14
print 'z ', id(z), sys.getrefcount(z)
del x
print 'PI', id(3.14), sys.getrefcount(3.14)

输出如下:

x  34645712 4
y  34645712 5
z  34645712 6
PI 34645712 5

我们看到,虽然引用计数的变化情况与我们想象中一样,但是值却有点不一样,对于这种现象,Python官网给出了解释:

sys.getrefcount(object)
Return the reference count of the object. The count returned is generally one higher than you might expect, because it includes the (temporary) reference as an argument to getrefcount().

2、拷贝:
从前面我们可以知道,对象赋值其实是简单的对象引用,拷贝操作可以导入Python的copy模块并调用内置函数完成,具体见下面代码:

#!/usr/bin/env python
import copy

def print_(arg):
    print id(arg),arg,'---',id(arg[2]),arg[2]

a = ['123', '456', [123,456]]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append('789'); a[2].insert(2,789)     // 修改列表
print_(a); print_(b); print_(c); print_(d)

输出如下:

140694526889784 ['123', '456', [123, 456, 789], '789'] --- 140694526920680 [123, 456, 789]
140694526889784 ['123', '456', [123, 456, 789], '789'] --- 140694526920680 [123, 456, 789]
140694527025592 ['123', '456', [123, 456, 789]] --- 140694526920680 [123, 456, 789]
140694526919672 ['123', '456', [123, 456]] --- 140694527027464 [123, 456]

关于引用有下面几点注意事项:
1)非容器类型(比如数字,字符串和其他“原子”类型的对象,像代码、类型和xrange对象等)没有拷贝一说。
2)如果元组变量只包含原子类型对象,对它的深拷贝不会进行,即此时深拷贝也为浅拷贝。

 

评论关闭