python基础知识5——赋值与深浅拷贝——整数和字符串,列表元组字典
深浅copy
和很多语言一样,Python中也分为简单赋值、浅拷贝、深拷贝这几种“拷贝”方式。
在学习过程中,一开始对浅拷贝理解很模糊。不过经过一系列的实验后,我发现对这三者的概念有了进一步的了解。
一、赋值
赋值算是这三种操作中最常见的了,我们通过一些例子来分析下赋值操作:
str例
- >>> a = 'hello'
- >>> b = 'hello'
- >>> c = a
- >>> [id(x) for x in a,b,c]
- [4404120000, 4404120000, 4404120000]
由以上指令中,我们可以发现a, b, c三者的地址是一样的。所以以上赋值的操作就相当于c = a = b = 'hello'。
赋值是系统先给一个变量或者对象(这里是'hello')分配了内存,然后再将地址赋给a, b, c。所以它们的地址是相同的。
list例
- >>> a = ['hello']
- >>> b = ['hello']
- >>> c = a
- >>> [id(x) for x in a,b,c]
- [4403975952, 4404095096, 4403975952]
但是这种情况却不一样了,a和b的地址不同。为何?
因为str是不可变的,所以同样是'hello'只有一个地址,但是list是可变的,所以必须分配两个地址。
这时,我们希望探究以上两种情况如果 修改值 会如何?
str例
- >>> a = 'world'
- >>> [id(x) for x in a,b,c]
- [4404120432, 4404120000, 4404120000]
- >>> print a, b, c
- world hello hello
这时a的地址和值变了,但是b, c地址和值都未变。因为str的不可变性,a要重新赋值则需重新开辟内存空间,所以a的值改变,a指向的地址改变。b, c由于'hello'的不变性,不会发生改变。
list例
- >>> a[0] = 'world'
- >>> [id(x) for x in a,b,c]
- [4403975952, 4404095096, 4403975952]
- >>> print a, b, c
- ['world'] ['hello'] ['world']
这时a, c的值和地址均改变,但二者仍相同,b不改变。由于list的可变性,所以修改list的值不需要另外开辟空间,只需修改原地址的值。所以a, c均改变。
在了解了以上的不同点之后,我们就能很好地分析浅拷贝和深拷贝了。
我们均用list作为例子。
二、浅拷贝
- >>> a = ['hello', [123, 234]]
- >>> b = a[:]
- >>> [id(x) for x in a,b]
- [4496003656, 4496066752]
- >>> [id(x) for x in a]
- [4496091584, 4495947536]
- >>> [id(x) for x in b]
- [4496091584, 4495947536]
Line3,4可以看出a, b地址不同,这符合list是可变的,应开辟不同空间。那浅拷贝就是拷贝了一个副本吗?再看Line5 - 8,我们发现a, b中元素的地址是相同的。如果说字符串'hello'地址一致还能理解,但是第二个元素是list地址仍一致。 这就说明了浅拷贝的特点,只是将容器内的元素的地址复制了一份 。
接着我们尝试修改a, b中的值:
- >>> a[0] = 'world'
- >>> a[1].append(345)
- >>> print 'a = ', a, '\n\r', 'b = ', b
- a = ['world', [123, 234, 345]]
- b = ['hello', [123, 234, 345]]
a中第一个元素str改变,但是b中未改变;a中第二个元素改变,b中也改变。这就符合不可变的对象修改会开辟新的空间,可变的对象修改不会开辟新空间。也进一步证明了 浅拷贝仅仅是复制了容器中元素的地址 。
三、深拷贝
- >>> from copy import deepcopy
- >>> a = ['hello', [123, 234]]
- >>> b = deepcopy(a)
- >>> [id(x) for x in a, b]
- [4496066824, 4496066680]
- >>> [id(x) for x in a]
- [4496091584, 4496067040]
- >>> [id(x) for x in b]
- [4496091584, 4496371792]
深拷贝后,可以发现a, b地址以及a, b中元素地址均不同。这才是完全 拷贝了一个副本 。
修改a的值后:
- >>> a[0] = 'world'
- >>> a[1].append(345)
- >>> print 'a = ', a, '\n\r', 'b = ', b
- a = ['world', [123, 234, 345]]
- b = ['hello', [123, 234]]
从Line4,5中可以发现仅仅a修改了,b没有任何修改。 因为b是一个完全的副本,元素地址均与a不同,a修改,b不受影响 。
总结:
1. 赋值是将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 )。
2. 浅拷贝是在另一块地址中创建一个新的变量或容器,但是容器内的元素的地址均是源对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素( 新瓶装旧酒 )。
3. 深拷贝是在另一块地址中创建一个新的变量或容器,同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本。也就是说( 新瓶装新酒 )。
- import copy
- a = [1, 2, 3, 4, ['a', 'b']] #原始对象
- b = a #赋值,传对象的引用
- c = copy.copy(a) #对象拷贝,浅拷贝
- d = copy.deepcopy(a) #对象拷贝,深拷贝
- a.append(5) #修改对象a
- a[4].append('c') #修改对象a中的['a', 'b']数组对象
- print 'a = ', a
- print 'b = ', b
- print 'c = ', c
- print 'd = ', d
- 输出结果:
- a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
- b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
- c = [1, 2, 3, 4, ['a', 'b', 'c']]
- d = [1, 2, 3, 4, ['a', 'b']]
一、数字和字符串
对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。
- 1 import copy
- 2 # ######### 数字、字符串 #########
- 3 n1 = 123
- 4 # n1 = "i am alex age 10"
- 5 print(id(n1))
- 6 # ## 赋值 ##
- 7 n2 = n1
- 8 print(id(n2))
- 9 # ## 浅拷贝 ##
- 10 n2 = copy.copy(n1)
- 11 print(id(n2))
- 12
- 13 # ## 深拷贝 ##
- 14 n3 = copy.deepcopy(n1)
- 15 print(id(n3))

二、其他基本数据类型
对于字典、元祖、列表 而言,进行赋值、浅拷贝和深拷贝时,其内存地址的变化是不同的。
1、赋值
赋值,只是创建一个变量,该变量指向原来内存地址,如:
- 1 n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
- 2
- 3 n2 = n1
2、浅拷贝
浅拷贝,在内存中只额外创建第一层数据
- 1 import copy
- 2
- 3 n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
- 4
- 5 n3 = copy.copy(n1)
3、深拷贝
深拷贝,在内存中将所有的数据重新创建一份(排除最后一层,即:python内部对字符串和数字的优化)
- 1 import copy
- 2
- 3 n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
- 4
- 5 n4 = copy.deepcopy(n1)
为什么要拷贝?
当进行修改时,想要保留原来的数据和修改后的数据
数字字符串 和 集合 在修改时的差异?(深浅拷贝不同的终极原因)
- 1 在修改数据时:
- 2 数字字符串:在内存中新建一份数据
- 3 集合:修改内存中的同一份数据
对于集合,如何保留其修改前和修改后的数据?
在内存中拷贝一份
对于集合,如何拷贝其n层元素同时拷贝?
深拷贝
- 1 浅copy
- 2 >>> dict = {"a":("apple",),"bo":{"b":"banna","o":"orange"},"g":["grape","grapefruit"]}
- 3 >>> dict = {"a":("apple",),"bo":{"b":"banna","o":"orange"},"g":["grape","grapefruit"]}
- 4 >>> dict2 = dict.copy()
- 5
- 6
- 7 >>> dict["g"][0] = "shuaige" #第一次我修改的是第二层的数据
- 8 >>> print dict
- 9 {'a': ('apple',), 'bo': {'b': 'banna', 'o': 'orange'}, 'g': ['shuaige', 'grapefruit']}
- 10 >>> print dict2
- 11 {'a': ('apple',), 'bo': {'b': 'banna', 'o': 'orange'}, 'g': ['shuaige', 'grapefruit']}
- 12 >>> id(dict["g"][0]),id(dict2["g"][0])
- 13 (140422980581296, 140422980581296) #从这里可以看出第二层他们是用的内存地址
- 14 >>>
- 15
- 16
- 17 >>> dict["a"] = "dashuaige" #注意第二次这里修改的是第一层
- 18 >>> print dict
- 19 {'a': 'dashuaige', 'bo': {'b': 'banna', 'o': 'orange'}, 'g': ['shuaige', 'grapefruit']}
- 20 >>> print dict2
- 21 {'a': ('apple',), 'bo': {'b': 'banna', 'o': 'orange'}, 'g': ['shuaige', 'grapefruit']}
- 22 >>>
- 23 >>> id(dict["a"]),id(dict2["a"])
- 24 (140422980580816, 140422980552272) #从这里看到第一层他们修改后就不会是相同的内存地址了!
- 25 >>>
- 26
- 27
- 28 #这里看下,第一次我修改了dict的第二层的数据,dict2也跟着改变了,但是我第二次我修改了dict第一层的数据dict2没有修改。
- 29 说明:浅copy只是第一层是独立的,其他层面是公用的!作用节省内存
- 30
- 31 深copy
- 32
- 33 >>> import copy #深copy需要导入模块
- 34 >>> dict = {"a":("apple",),"bo":{"b":"banna","o":"orange"},"g":["grape","grapefruit"]}
- 35 >>> dict2 = copy.deepcopy(dict)
- 36 >>> print dict
- 37 {'a': ('apple',), 'bo': {'b': 'banna', 'o': 'orange'}, 'g': ['grape', 'grapefruit']}
- 38 >>> print dict2
- 39 {'a': ('apple',), 'bo': {'b': 'banna', 'o': 'orange'}, 'g': ['grape', 'grapefruit']}
- 40 >>> dict["g"][0] = "shuaige" #修改第二层数据
- 41 >>> print dict
- 42 {'a': ('apple',), 'bo': {'b': 'banna', 'o': 'orange'}, 'g': ['shuaige', 'grapefruit']}
- 43 >>> print dict2
- 44 {'a': ('apple',), 'bo': {'b': 'banna', 'o': 'orange'}, 'g': ['grape', 'grapefruit']}
- 45 >>> id(dict["g"][0]),id(dict2["g"][0])
- 46 (140422980580816, 140422980580288) #从这里看到第二个数据现在也不是公用了
- 47
- 48 # 通过这里可以看出他们现在是一个完全独立的,当你修改dict时dict2是不会改变的因为是两个独立的字典!
python基础知识5——赋值与深浅拷贝——整数和字符串,列表元组字典的更多相关文章
- Python第三天 序列 数据类型 数值 字符串 列表 元组 字典
Python第三天 序列 数据类型 数值 字符串 列表 元组 字典 数据类型数值字符串列表元组字典 序列序列:字符串.列表.元组序列的两个主要特点是索引操作符和切片操作符- 索引操作符让我 ...
- Python第三天 序列 5种数据类型 数值 字符串 列表 元组 字典 各种数据类型的的xx重写xx表达式
Python第三天 序列 5种数据类型 数值 字符串 列表 元组 字典 各种数据类型的的xx重写xx表达式 目录 Pycharm使用技巧(转载) Python第一天 安装 shell ...
- 【python】变量的赋值、深浅拷贝
python——赋值与深浅拷贝 https://www.cnblogs.com/Eva-J/p/5534037.html 啥都不说,看这个博主的文章!
- python基础知识-7-内存、深浅、文件操作
python其他知识目录 1.一些对内存深入理解的案例 以下列举列表,列表/字典/集合这些可变类型都是一样的原理 变量是个地址,指向存储数据的内存空间的地址,它的实质就相当于c语言里的指针.变量和数据 ...
- python基础-3 集合 三元运算 深浅拷贝 函数 Python作用域
上节课总结 1 运算符 in 字符串 判断 : “hello” in "asdasfhelloasdfsadf" 列表元素判断:"li" in ['li', ...
- Python自动化开发 - 字符串, 列表, 元组, 字典和和文件操作
一.字符串 特性:字符串本身不可修改,除非字符串变量重新赋值.Python3中所有字符串都是Unicode字符串,支持中文. >>> name = "Jonathan&q ...
- python字符串/列表/元组/字典之间的相互转换(5)
一.字符串str与列表list 1.字符串转列表 字符串转为列表list,可以使用str.split()方法,split方法是在字符串中对指定字符进行切片,并返回一个列表,示例代码如下: # !usr ...
- Python 整数 长整数 浮点数 字符串 列表 元组 字典的各种方法
对于Python, 一切事物都是对象,对象基于类创建!! 注:查看对象相关成员var,type, dir 一.整数 如: 18.73.84 每一个整数都具备如下需要知道的功能: def bit_len ...
- Python笔记【5】_字符串&列表&元组&字典之间转换学习
#!/usr/bin/env/python #-*-coding:utf-8-*- #Author:LingChongShi #查看源码Ctrl+左键 #数据类型之间的转换 Str='www.baid ...
随机推荐
- 基于服务(Web Service)的文件管理Winform程序实现
1. 描述 面向服务的体系结构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.接口是采用中立的方式进行定义的,它应该独立于实现 ...
- java容器的一些存取用法
关于集合(list,set,map)的遍历与增强for循环的使用 java集合类的使用可以说是无处不在,总的我们可以将之分为三大块,分别是从Collection接口延伸出的List.Set和以 ...
- AWS CloudFormation Template
{ "AWSTemplateFormatVersion" : "2010-09-09", "Parameters" : { "Ba ...
- Building GCC 4.1.2 in CentOS 7 for Maya API development
Following the official guid: http://help.autodesk.com/cloudhelp/2015/ENU/Maya-SDK/files/Setting_up_y ...
- expr命令的一些用法
expr是evaluate expressions的缩写,我的理解它的作用就是用来输出表达式的值. 看下面的几个例子. (1)进行数值运算 $:expr 1 + 2 //'+' 左右两边必须有 ...
- 在Eclipse中使用JUnit4进行单元测试(中级篇)
我们继续对初级篇中的例子进行分析.初级篇中我们使用Eclipse自动生成了一个测试框架,在这篇文章中,我们来仔细分析一下这个测试框架中的每一个细节,知其然更要知其所以然,才能更加熟练地应用JUnit4 ...
- windows和linux实现文件共享
linux和windows实现共享,需要安装samba服务器 安装步骤: 1.查看是否已经安装samba rpm -q samba 2.如果已经安装,如果你想再次安装,可以卸载 rpm -e samb ...
- vs2010下C++调用lib或dll文件
注: DLL:表示链接库,包含dll,lib文件: dll: 表示my.dll文件 lib: 表示my.lib文件 C++ 调用.lib的方法: 一: 隐式的加载时链接,有三种方法 1 设置工程的 ...
- win7(64位)php5.5-Apache2.4-mysql5.6环境安装
原文链接http://jingyan.baidu.com/article/9faa723152c5d6473d28cb47.html 工具/原料 php-5.5.10-Win32-VC11-x64.z ...
- 检测文件是否有BOM 头,并删除BOM头(php)
将下面文件放在网站根目录访问即可,它会遍历当前目录下所有子目录,检测文件是否含有BOM头,并删除BOM头 <?php //remove the utf-8 boms //by magicbug ...