这次算不上什么技巧分享,只是在碰到了一个bug之后整理的东西,希望各位在看过之后不会在犯同样的错误。
首先,还是用同为解释型语言的PHP开刀:
php > $a = array(1,2,3); php > $b = array($a,$a); php > print_r($b); Array ( [0] => Array ( [0] => 1 [1] => 2 [2] => 3 ) [1] => Array ( [0] => 1 [1] => 2 [2] => 3 ) ) php > array_pop($a); php > print_r($b); Array ( [0] => Array ( [0] => 1 [1] => 2 [2] => 3 ) [1] => Array ( [0] => 1 [1] => 2 [2] => 3 ) )
很合乎情理,根据array $a创建了array $b,$a的任何变动不会直接影响到$b。
同样的代码换作Python就有问题了:
>>> a = [1,2,3] >>> b = [a,a] >>> b [[1, 2, 3], [1, 2, 3]] >>> a.pop() 3 >>> b [[1, 2], [1, 2]] >>>
list a的变化直接影响到了了list b,可见python对于对象的是指针引用而不是直接附值。如果用PHP来模拟这个方法则:
php > $b=array(&$a,&$a); php > print_r($b); Array ( [0] => Array ( [0] => 1 [1] => 2 ) [1] => Array ( [0] => 1 [1] => 2 ) ) php > array_pop($a); php > print_r($b); Array ( [0] => Array ( [0] => 1 ) [1] => Array ( [0] => 1 ) )
既然如此,尝试下一个2B的方法:
>>> b = [a[:],a[:]] >>> b [[1, 2], [1, 2]] >>> a.pop() 2 >>> b [[1, 2], [1, 2]]
尽管真的很2,但貌似可以解决这个问题,但这只是很简答的2层嵌套,换作更多的嵌套如何?
>>> import copy >>> a = [1,2,3] >>> b = copy.deepcopy([a,a]) >>> b [[1, 2, 3], [1, 2, 3]] >>> a.pop() 3 >>> a [1, 2] >>> b [[1, 2, 3], [1, 2, 3]]
copy这个类包实现了这个功能,需要说明的是同样有个copy.copy方法,与deepcopy不同的是它仅仅只是“表层copy”,对于更多层级的嵌套一样会出问题,好吧,我承认,我遇到的bug就是错误的使用了copy.copy而不是copy.deepcopy
捎带说说两个P语言之间的设计差异。PHP是“用完即销毁”的线程模型,所以对于变量的使用尽量简单,这样不容出错。Python的内部变量都是采用指针传递+计数器计数的方式 ,这样可以尽可能的节省内存,但弊端就是这种稀奇古怪的问题。
转载请注明:爱开源 » Python中的对象复制