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是对象,对象中含有引用变量,所以当对象中的引用变量发送改变则其浅拷贝也会发送改变