最新消息:

Python中的对象复制

python admin 2699浏览 0评论

这次算不上什么技巧分享,只是在碰到了一个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中的对象复制

您必须 登录 才能发表评论!