Python那些让我疑惑许久的代码--2

疑惑代码–1

import copy
lst1=[1,2,[3,4]]
lst2=lst1
lst3=copy.copy(lst1)
lst4=copy.deepcopy(lst1)
lst1.append([5,6])
print(lst1) #[1, 2, [3, 4], [5, 6]]
print(lst2) #[1, 2, [3, 4], [5, 6]]
print(lst3) #[1, 2, [3, 4]]
print(lst4) #[1, 2, [3, 4]]
lst1[0]=6
print(lst1) #[6, 2, [3, 4], [5, 6]]
print(lst2) #[6, 2, [3, 4], [5, 6]]
print(lst3) #[1, 2, [3, 4]]
print(lst4) # [1, 2, [3, 4]]
lst1[2][0]=4
print(lst1) #[6, 2, [4, 4], [5, 6]]
print(lst2) #[6, 2, [4, 4], [5, 6]]
print(lst3) #[1, 2, [4, 4]]
print(lst4) #[1, 2, [3, 4]]

疑惑点

  • lst2,lst3,lst4的结果随lst1的改变为什么出现的是这样的结果?
  • c++中的 深拷贝,浅拷贝与python的概率是一样的吗?

解决疑惑点

lst2,lst3,lst4的结果随lst1的改变为什么出现的是这样的结果?

在解释前必须要了解的知识点就是lst2,lst3,lst4分别代表的是什么?

  • lst2代表lst1的别名
  • lst3代表浅拷贝
  • lst4代表深拷贝

从上面我们引申了三个概率

  • 别名
  • 浅拷贝
  • 深拷贝
别名

别名这个概念是我在 <<流程的python>>这本书中所看到的,这个说明其实很形象了,例如看过NBA的人都知道小皇帝—>勒布朗·詹姆斯,死神—>杜兰特,萌神(勉扣冠军)—>库里,甜瓜–>安东尼等超级巨星,当我们想到死神时必然会想到杜兰特,nba死神等价于杜兰特,lst2和上面的例子一样lst2等价于lst1,他们只是变了一个变量名称而已,但是都是同一个,所以lst1变了,lst2肯定会变,上面的话语是简单易懂的话语,现在用专业的话语表示为lst2和lst1用的是同一个地址
在这里插入图片描述
现在引申另一个问题,为什么lst2=lst1就是让lst1的地址等于lst2
这里我们可以用go语言或者其他语言对于变量分类来介绍,python中列表的赋值是引用传递即赋值是以地址的形式赋值,而另一个传递方式则为值传递,值传递则就是传递值了

在这里插入图片描述

常见的引用变量(可变)

字典,列表,数组

常见的值变量(不可变)

数字,字符串,元组等

浅拷贝

浅拷贝与别名的区别在于lst1和lst3的地址是不同的但是lst1中如果还有引用变量的,则lst3中的引用变量会共用同一个地址
在这里插入图片描述
所以当引用变量中的引用变量发送改变,浅拷贝也会发送改变

深拷贝

深拷贝和浅拷贝就完全不一样的,他会将该变量全部重新创建新的地址,不管引用变量中是否还有引用变量,其地址都是不一样的
在这里插入图片描述

c++中的 深拷贝,浅拷贝与python的概率是一样的吗?

c++的深拷贝,浅拷贝代码

#include <iostream>
#include<cstring>

using namespace std;

class STRING
{
public:
    STRING( const char* s = "" ) :_str( new char[strlen(s)+1] )

    {
        strcpy_s( _str, strlen(s)+1, s );
    }
    //STRING( const STRING& s )
    //{
    //    //_str = s._str; //浅拷贝的写法
    //    cout << "拷贝构造函数" << endl;
    //    _str = new char[strlen(s._str) + 1];
    //    strcpy_s( _str, strlen(s._str) + 1, s._str );
    //}
    //STRING& operator=(const STRING& s)
    //{
    //    cout << "运算符重载" << endl;
    //    if (this != &s)
    //    {
    //        //this->_str = s._str; //浅拷贝的写法
    //        delete[] _str;
    //        this->_str = new char[strlen(s._str) + 1];
    //        strcpy_s(this->_str, strlen(s._str) + 1, s._str);
    //    }
    //    return *this;
    //}

    STRING( const STRING& s ):_str(NULL)
    {
        STRING tmp(s._str);// 调用了构造函数,完成了空间的开辟以及值的拷贝
        swap(this->_str, tmp._str); //交换tmp和目标拷贝对象所指向的内容
    }

    STRING& operator=(const STRING& s)
    {
        if ( this != &s )//不让自己给自己赋值
        {
            STRING tmp(s._str);//调用构造函数完成空间的开辟以及赋值工作
            swap(this->_str, tmp._str);//交换tmp和目标拷贝对象所指向的内容
        }
        return *this;
    }

    ~STRING()
    {
        cout << "~STRING" << endl;
        if (_str)
        {
            delete[] _str;
            _str = NULL;
        }
    }

    void show()
    {
        cout << _str << endl;
    }
private:
    char* _str;
};

int main()
{
    //STRING s1("hello linux");
    //STRING s2(s1);
    //STRING s2 = s1;
    //s2.show();
    const char* str = "hello linux!";
    STRING  s1(str);
    STRING s2;
    s2 = s1;
    s1.show();
    s2.show();

    return 0;
}

python的深拷贝,浅拷贝代码

import copy
class Test:
    def __init__(self):
        self.lst=[1,2,3]
    def __str__(self):
        return str(self.lst)
t=Test()
t2=t
t3=copy.copy(t)
t4=copy.deepcopy(t)
t.lst[1]=1
print(t,id(t)) #[1, 1, 3] 1399649404352
print(t2,id(t2)) #[1, 1, 3] 1399649404352
print(t3,id(t3)) #[1, 1, 3] 1399649404296
print(t4,id(t4)) #[1, 2, 3] 1399651116928

c++和python的差不多,都是当用到引用变量,浅拷贝都会共用同一个地址,而深拷贝则都是重新创建地址
可能会有人疑问python中t3为什么地址明明不一样但是也发送了改变,其实这里因为t3是对象,对象中含有引用变量,所以当对象中的引用变量发送改变则其浅拷贝也会发送改变
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值