3.python基础补充(集合,collection系列,深浅拷贝)
一.集合
1.集合(set):
把不同的元素组成一起形成集合,是python基本的数据类型。集合元素(set elements):组成集合的成员
python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)等数学运算.
sets 支持 x in set, len(set),和 for x in set。作为一个无序的集合,sets不记录元素位置或者插入点。因此,sets不支持 indexing, slicing, 或其它类序列(sequence-like)的操作。
2.集合的创建
1 2 3 4 5 6 7 8 9 10 11 | se = set ([ 11 , 22 , 33 , 44 ]) print (se) { 33 , 11 , 44 , 22 } print ( type (se)) < class 'set' > 或者 >>> se = { 'huang' , 'xu' } >>> se { 'xu' , 'huang' } >>> type (se) < class 'set' > |
集合的使用
具体用法:
1.add(添加元素)
1 2 3 | >>> se.add( '123' ) >>> se { 'xu' , 'huang' , '123' } |
2.clear(清空集合)
1 2 3 | >>> se.clear() >>> se set () |
3.copy(浅拷贝)
1 2 3 4 | >>> se_1 = { 'huang' , 'xu' } >>> se_2 = se_1.copy() >>> se_2 { 'xu' , 'huang' } |
4.difference差异比较
1 2 3 4 5 6 7 8 | >>> se_1 = { 'huang' , 'xu' , 'shi' , 'shei' } >>> se_2 = { 'haode' , 'shi' , 'huang' } #取出se_2中在se_1所没有的元素 >>> se_1.difference(se_2) { 'xu' , 'shei' } #取出se_1中在se_2所没有的元素 >>> se_2.difference(se_1) { 'haode' } |
5.difference_update差异更新
1 2 3 4 5 6 7 | >>> se_1 { 'shi' , 'xu' , 'huang' } >>> se_2 { 'shi' , 'huang' , 'haode' } >>> se_1.difference_update(se_2) >>> se_1 { 'xu' } |
6.discard移除指定元素
1 2 3 4 5 | >>> se_1 { 'shi' , 'xu' , 'shei' , 'huang' } >>> se_1.discard( 'shei' ) >>> se_1 { 'shi' , 'xu' , 'huang' } |
7.intersection取交集并且建立新的集合
1 2 3 4 | >>> se_1={ 'huang' , 'xu' , 'shi' , 'sha' , 'bi' } >>> se_2={ 'huang' , 'xu' , 'shi' , 'er' , 'bi' } >>> se_1.intersection(se_2) { 'huang' , 'shi' , 'xu' , 'bi' } |
8.intersection_update取交集并且更新原来的集合
1 2 3 4 5 | >>> se_1 = { 'huang' , 'xu' , 'shi' , 'sha' , 'bi' } >>> se_2 = { 'huang' , 'xu' , 'shi' , 'er' , 'bi' } >>> se_1.intersection_update(se_2) >>> se_1 { 'huang' , 'shi' , 'xu' , 'bi' } |
9.isdisjoint判断没有交集,没有返回true,有返回false
1 2 3 4 5 6 7 8 9 10 11 | >>> se_1={ 'huang' , 'xu' , 'shi' , 'sha' , 'bi' } >>> se_2={ 'huang' , 'xu' , 'shi' , 'er' , 'bi' } >>> se_1.isdisjoint(se_2) False >>> se_2.isdisjoint(se_1) False 或 >>> se_1={ 'huang' , 'xu' } >>> se_2={ 'huangg' , 'xuu' } >>> se_2.isdisjoint(se_1) True |
10.issubset判断是否为子集
1 2 3 4 5 | >>> se_1 = { 'huang' , 'xu' } >>> se_2 = { 'huang' , 'xu' , 'shabi' } #判断se_1是否为se_2的子集 >>> se_1.issubset(se_2) True |
11.issuperset判断是否为父集
1 2 3 4 5 6 7 8 9 | >>> se_1 = { 'huang' , 'xu' } >>> se_2 = { 'huang' , 'xu' , 'shabi' } #判断se_1是否为se_2的父集 >>> se_1.issuperset(se_2) False #判断se_2是否为se_1的父集 >>> se_2.issuperset(se_1) True >>> |
12.pop移除集合元素
1 2 3 | >>> se_1 = { 'huang' , 'xu' , 'sha' , 'bi' } >>> se_1.pop() 'sha' |
13.remove删除指定元素集合
1 2 3 4 5 | >>> se_1 = { 'huang' , 'xu' , 'sha' , 'bi' } >>> se_1.remove( 'bi' ) >>> se_1 { 'sha' , 'liu' , 'yao' } >>> |
14.symmetric_difference取两个集合的差集,并建立新的元素
1 2 3 4 5 6 7 | >>> se_1 = { 'huang' , 'xu' , 'sha' , 'bi' } >>> se_2 = { 'huang' , 'xu' , 'shabi' } >>> se_1.symmetric_difference(se_2) { 'sha' , 'shabi' , 'bi' } >>> b = se_1.symmetric_difference(se_2) >>> b { 'sha' , 'shabi' , 'bi' } |
15.symmetric_difference_update取两个集合的差集,更新原来的集合对象
1 2 3 4 5 | >>> se_1 = { 'huang' , 'xu' , 'sha' , 'bi' } >>> se_2 = { 'huang' , 'xu' , 'shabi' } >>> se_1.symmetric_difference_update(se_2) >>> se_1 { 'sha' , 'shabi' , 'bi' } |
16.union并集
1 2 3 4 5 6 | >>> se_1 { 'sha' , 'shabi' , 'bi' } >>> se_2 { 'shabi' , 'huang' , 'xu' } >>> se_1.union(se_2) { 'xu' , 'sha' , 'shabi' , 'huang' , 'bi' } |
17.update更新集合
1 2 3 4 5 | >>> se_1 { 'sha' , 'shabi' , 'bi' } >>> se_1.update( 'liuxu' ) >>> se_1 { 'x' , 'u' , 'shabi' , 'bi' , 'u' , 'i' , 'sha' , 'l' , 'a' } |
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | old_dict = { "#1" :{ 'hostname' : 'c1' , 'cpu_count' : 2 , 'mem_capicity' : 80 }, "#2" :{ 'hostname' : 'c1' , 'cpu_count' : 2 , 'mem_capicity' : 80 }, "#3" :{ 'hostname' : 'c1' , 'cpu_count' : 2 , 'mem_capicity' : 80 } } new_dict = { "#1" :{ 'hostname' : 'c1' , 'cpu_count' : 2 , 'mem_capicity' : 800 }, "#3" :{ 'hostname' : 'c1' , 'cpu_count' : 2 , 'mem_capicity' : 80 }, "#4" :{ 'hostname' : 'c2' , 'cpu_count' : 2 , 'mem_capicity' : 80 } } #获取old_dict元素 old = set (old_dict.keys()) print (old) #获取new_dict元素 new = set (new_dict.keys()) print (new) #要更新的集合元素(交集) update_set = old.intersection(new) print (update_set) #获取要删除的集合元素(差集) delete_set = old.difference(new) print (delete_set) #获取要添加的集合元素() add_set = new.difference(update_set) print (add_set) |
二.collection系列
collections模块自Python 2.4版本开始被引入,包含了dict、set、list、tuple以外的一些特殊的容器类型,分别是:
OrderedDict类:排序字典,是字典的子类。引入自2.7。
namedtuple()函数:命名元组,是一个工厂函数。引入自2.6。
Counter类:为hashable对象计数,是字典的子类。引入自2.7。
deque:双向队列。引入自2.4。
defaultdict:使用工厂函数创建字典,使不用考虑缺失的字典键。引入自2.5。
文档参见:http://docs.python.org/2/library/collections.html
使用的时候需要用import导入collections模块
1.计数器(counter)
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。
(1)创建
创建一个空的Counter类
1 2 3 4 5 6 7 8 9 | import collections c = collections.Counter() # 创建一个空的Counter类 print (c) c = collections.Counter( 'asdfghjjhgfdqwer' ) print (c) c = collections.Counter({ 'a' : 4 , 'b' : 2 }) #从一个字典对象创建 print (c) c = collections.Counter(a = 4 , b = 2 ) # 从一组键值对创建 print (c) |
结果:
1 2 3 4 | Counter() Counter({ 'd' : 2 , 'f' : 2 , 'h' : 2 , 'g' : 2 , 'j' : 2 , 's' : 1 , 'a' : 1 , 'r' : 1 , 'q' : 1 , 'e' : 1 , 'w' : 1 }) Counter({ 'a' : 4 , 'b' : 2 }) Counter({ 'a' : 4 , 'b' : 2 }) |
(2).计数值的访问
当所访问的键不存在时,返回0,而不是KeyError;否则返回它的计数。
1 2 3 4 5 6 7 8 9 | >>> import collections >>> c = collections.Counter( 'asdfgdsasdf' ) >>> c[ 'a' ] 2 >>> c[ 'h' ] 0 >>> c[ 's' ] 3 >>> |
(3).计数器的更新与减少
1.update()更新
1 2 3 4 5 6 | >>> c Counter({ 's' : 3 , 'd' : 3 , 'a' : 2 , 'f' : 2 , 'g' : 1 }) >>> c = collections.Counter( 'update' ) >>> c.update( 'update' ) >>> c Counter({ 'a' : 2 , 'e' : 2 , 'd' : 2 , 'p' : 2 , 'u' : 2 , 't' : 2 }) |
2.subtract()减少
1 2 3 4 5 6 7 | >>> c = collections.Counter( 'subtract' ) >>> c Counter({ 't' : 2 , 'a' : 1 , 'c' : 1 , 'b' : 1 , 's' : 1 , 'r' : 1 , 'u' : 1 }) >>> c.subtract( 'subtract' ) >>> c Counter({ 'a' : 0 , 'c' : 0 , 'b' : 0 , 's' : 0 , 'r' : 0 , 'u' : 0 , 't' : 0 }) >>> |
(4)键的删除
当计数值为0时,并不意味着元素被删除,删除元素应当使用del
1 2 3 4 5 6 7 8 | >>> c = collections.Counter( 'abcdcba' ) >>> c[ 'b' ] = 0 >>> c Counter({ 'a' : 2 , 'c' : 2 , 'd' : 1 , 'b' : 0 }) >>> del c[ 'a' ] >>> c Counter({ 'c' : 2 , 'd' : 1 , 'b' : 0 }) >>> |
(5) 迭代器
返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。所有元素按照字母序排序,个数小于1的元素不被包含。
1 2 3 4 | >>> c = collections.Counter( 'abcdcba' ) >>> list (c.elements()) [ 'a' , 'a' , 'c' , 'c' , 'b' , 'b' , 'd' ] >>> |
(5)most_common([n])
返回一个TopN列表。如果n没有被指定,则返回所有元素。当多个元素计数值相同时,按照字母序排列。
1 2 3 | >>> c = collections.Counter( 'abcdcba' ) >>> c.most_common() [( 'a' , 2 ), ( 'c' , 2 ), ( 'b' , 2 ), ( 'd' , 1 )] |
(6)浅拷贝
1 2 3 4 5 6 7 | >>> c = collections.Counter( 'abcdcba' ) >>> c Counter({ 'a' : 2 , 'c' : 2 , 'b' : 2 , 'd' : 1 }) >>> cc = c.copy() >>> cc Counter({ 'a' : 2 , 'c' : 2 , 'b' : 2 , 'd' : 1 }) >>> |
(7)算术与集合操作
+、-、&、|操作也可以用于Counter。其中&和|操作分别返回两个Counter对象各元素的最小值和最大值。需要注意的是,得到的Counter对象将删除小于1的元素。
1 2 3 4 5 6 7 8 9 10 | >>> c = collections.Counter(a = 3 , b = 1 ) >>> d = collections.Counter(a = 1 , b = 2 ) >>> c + d Counter({ 'a' : 4 , 'b' : 3 }) >>> c - d Counter({ 'a' : 2 }) >>> c&d Counter({ 'a' : 1 , 'b' : 1 }) >>> c|d Counter({ 'a' : 3 , 'b' : 2 }) |
一些Counter类的常用操作,来源于Python官方文档
1 2 3 4 5 6 7 8 9 | sum (c.values()) # 所有计数的总数 c.clear() # 重置Counter对象,注意不是删除 list (c) # 将c中的键转为列表 set (c) # 将c中的键转为set dict (c) # 将c中的键值对转为字典 c.items() # 转为(elem, cnt)格式的列表 Counter( dict (list_of_pairs)) # 从(elem, cnt)格式的列表转换为Counter类对象 c.most_common()[: - n: - 1 ] # 取出计数最少的n个元素 c + = Counter() # 移除0和负值 |
2.有序字典(orderedDict )
有序字典继承字典的一切属性,只是在顺序上是有序的。
1 2 3 4 5 6 | >>> import collections >>> info = collections.OrderedDict({ 'name' : 'huangxu' , 'age' : 21 }) >>> info OrderedDict([( 'age' , 21 ), ( 'name' , 'huangxu' )]) >>> type (info) < class 'collections.OrderedDict' > |
1 2 3 4 5 6 7 8 | import collections info = collections.OrderedDict(name = 'huangxu' ,age = '21' ,job = 'IT' ) print (info) print (info.keys()) print (info.values()) OrderedDict([( 'age' , '21' ), ( 'name' , 'huangxu' ), ( 'job' , 'IT' )]) odict_keys([ 'age' , 'name' , 'job' ]) odict_values([ '21' , 'huangxu' , 'IT' ]) |
一些功能:
(1).move_to_end将指定的键值对从开头移动到末尾。
1 2 3 4 5 | >>> import collections >>> info = collections.OrderedDict(name = 'liuyao' ,age = '21' ,job = 'IT' ) >>> info.move_to_end( 'name' ) >>> info OrderedDict([( 'age' , '21' ), ( 'job' , 'IT' ), ( 'name' , 'huangxu' )]) |
(2).pop删除字典键值,返回删除的键值的values
1 2 3 4 5 6 | >>> info = collections.OrderedDict(name = 'huangxu' ,age = '21' ,job = 'IT' ) >>> info.pop( 'job' ) 'IT' >>> info OrderedDict([( 'age' , '21' ), ( 'name' , 'huangxu' )]) >>> |
(3).clear清除有序字典的值
1 2 3 4 | >>> info = collections.OrderedDict(name = 'huangxu' ,age = '21' ,job = 'IT' ) >>> info.clear() >>> info OrderedDict() |
1 2 3 4 5 6 7 8 9 10 | import collections info = collections.OrderedDict(name = 'huangxu' ,age = '21' ,job = 'IT' ) print (info) print (info.keys()) print (info.values()) print (info.items()) OrderedDict([( 'age' , '21' ), ( 'job' , 'IT' ), ( 'name' , 'huangxu' )]) odict_keys([ 'age' , 'job' , 'name' ]) odict_values([ '21' , 'IT' , 'huangxu' ]) odict_items([( 'age' , '21' ), ( 'job' , 'IT' ), ( 'name' , 'huangxu' )]) |
3.默认字典(defaultdict)
这里的defaultdict(function_factory)构建的是一个类似dictionary的对象,其中keys的值,自行确定赋值,但是values的类型,是function_factory的类实例,而且具有默认值。比如default(int)则创建一个类似dictionary对象,里面任何的values都是int的实例,而且就算是一个不存在的key, d[key] 也有一个默认值,这个默认值是int()的默认值0.
defaultdict是对字典的类型的补充,他默认给字典的值设置了一个类型。创建一个默认字典,value值类型为列表.dic = collections.defaultdict(list)
例:
1 2 3 4 5 6 7 8 | import collections s = [( 'yellow' , 1 ), ( 'blue' , 2 ), ( 'yellow' , 3 ), ( 'blue' , 4 ), ( 'red' , 1 )] d = collections.defaultdict( list ) for k, v in s: d[k].append(v) list (d.items()) |
defaultdict可以接受一个内建函数list作为参数。其实呢,list()本身是内建函数,但是再经过更新后,python里面所有东西都是对象,所以list改编成了类,引入list的时候产生一个类的实例。
1 2 3 4 5 6 7 8 | import collections dic = collections.defaultdict( list ) dic[ 'k1' ] print (dic) print (dic.keys()) print (dic.values()) dic[ 'k1' ].append( 'v1' ) print (dic.values()) |
一些具有的方法:
1.copy拷贝
1 2 3 4 5 6 7 8 9 10 | import collections dic = collections.defaultdict( list ) dic[ 'k1' ] dic[ 'k1' ].append( 'v1' ) print (dic) dic_1 = dic.copy() print (dic_1) #结果 defaultdict(< class 'list' >, { 'k1' : [ 'v1' ]}) defaultdict(< class 'list' >, { 'k1' : [ 'v1' ]}) |
4.可命名元组(namedtuple)
没有现成的类,用户需要自行创建相应的类
1 2 3 4 5 6 7 8 | import collections tu = collections.namedtuple( 'tu' ,[ 'x' , 'y' , 'z' ]) #创建一个类,类名为Point yao_tu = tu( 11 , 22 , 33 ) print (yao_tu) print (yao_tu.x) #直接通过命名元素去访问元组对应的元素, print (yao_tu[1 ]) #等同于上面这种方式,但是没有上面这种方式可读性强 print (yao_tu.y) print (yao_tu.z) |
5.双向队列(deque)
(1)创建一个队列
1 2 3 | import collections que = collections.deque([ 'sb' , 'huang' , 'xu' ]) print (que) |
(2)追加元素到队列
1 2 3 4 5 6 | >>> que.append( 'wo' ) >>> que deque([ 'sb' , 'huang' , 'xu' , 'wo' ]) >>> que.append([ 'ni' , 'ta' ]) >>> que deque([ 'sb' , 'huang' , 'xu' , 'wo' , [ 'ni' , 'ta' ]]) |
(3)追加元素到队列左侧
1 2 3 | >>> que.appendleft( 'zuo' ) >>> que deque([ 'zuo' , 'sb' , 'huang' , 'xu' , 'wo' , [ 'ni' , 'ta' ]]) |
(4)统计元素个数
1 2 3 4 5 6 | >>> que.appendleft( 'zuo' ) >>> que deque([ 'zuo' , 'sb' , 'huang' , 'xu' , 'wo' , [ 'ni' , 'ta' ]]) >>> que.appendleft( 'zuo' ) >>> que.count( 'zuo' ) 2 |
(4)清除
1 2 3 | >>> que.clear() >>> que deque([]) |
(5)extend扩展元素
1 2 3 4 5 6 | >>> que = collections.deque([ 'sb' , 'huang' , 'xu' ]) >>> que deque([ 'sb' , 'huang' , 'xu' ]) >>> que.extend([ 'a' , 'b' , 'c' ]) >>> que deque([ 'sb' , 'huang' , 'xu' , 'a' , 'b' , 'c' ]) |
(6)extendleft从左侧扩展
1 2 3 4 5 | >>> que deque([ 'sb' , 'huang' , 'xu' , 'a' , 'b' , 'c' , 'zuo1' , 'zuo2' , 'zuo3' ]) >>> que.extendleft([ 'zuo4' , 'zuo5' , 'zuo6' ]) >>> que deque([ 'zuo6' , 'zuo5' , 'zuo4' , 'sb' , 'huang' , 'xu' , 'a' , 'b' , 'c' , 'zuo1' , 'zuo2' , 'zuo3' ]) |
(7)pop删除
1 2 3 4 5 6 | >>> que deque([ 'zuo6' , 'zuo5' , 'zuo4' , 'sb' , 'huang' , 'xu' , 'a' , 'b' , 'c' , 'zuo1' , 'zuo2' , 'zuo3' ]) >>> que.pop() 'zuo3' >>> que deque([ 'zuo6' , 'zuo5' , 'zuo4' , 'sb' , 'huang' , 'xu' , 'a' , 'b' , 'c' , 'zuo1' , 'zuo2' ]) |
(8)popleft从左侧开始删除
1 2 3 4 5 6 | >>> que deque([ 'zuo6' , 'zuo5' , 'zuo4' , 'sb' , 'huang' , 'xu' , 'a' , 'b' , 'c' , 'zuo1' , 'zuo2' ]) >>> que.popleft() 'zuo6' >>> que deque([ 'zuo5' , 'zuo4' , 'sb' , 'huang' , 'xu' , 'a' , 'b' , 'c' , 'zuo1' , 'zuo2' ]) |
(9)reverse顺序反转
1 2 3 4 5 | >>> que deque([ 'zuo5' , 'zuo4' , 'sb' , 'huang' , 'xu' , 'a' , 'b' , 'c' , 'zuo1' , 'zuo2' ]) >>> que.reverse() >>> que deque([ 'zuo2' , 'zuo1' , 'c' , 'b' , 'a' , 'xu' , 'huang' , 'sb' , 'zuo4' , 'zuo5' ]) |
(10)remove删除指定元素
1 2 3 4 5 | >>> que deque([ 'zuo2' , 'zuo1' , 'c' , 'b' , 'a' , 'xu' , 'huang' , 'sb' , 'zuo4' , 'zuo5' ]) >>> que.remove( 'sb' ) >>> que deque([ 'zuo2' , 'zuo1' , 'c' , 'b' , 'a' , 'xu' , 'huang' , 'zuo4' , 'zuo5' ]) |
(11)rotate将队列末尾4个元素反转到队列左侧
1 2 3 4 5 | >>> que deque([ 'zuo5' , 'zuo2' , 'zuo1' , 'c' , 'b' , 'a' , 'xu' , 'huang' , 'zuo4' ]) >>> que.rotate( 4 ) >>> que deque([ 'a' , 'xu' , 'huang' , 'zuo4' , 'zuo5' , 'zuo2' , 'zuo1' , 'c' , 'b' ]) |
6.单向队列 queue(先进先出 FIFO )
(1)创建
1 2 3 4 5 6 | >>> import queue >>> que = queue.Queue( 2 ) >>> que <queue.Queue object at 0x7f70678ec550 > >>> >>> que = queue.Queue(maxsize = 10 ) |
queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。
(3)放入任务
1 2 | >>> que.put([ 'a' , 'd' ]) >>> que |
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。
(3)从队列中取值
1 2 3 4 | >>> que.put([ 'a' , 'd' ]) >>> que.get() [ 'a' , 'd' ] >>> |
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。
(3)返回队列大小
1 2 | >>> que.qsize() 1 |
(4)判断队列为空返回True,反之False
1 2 3 | >>> que.empty() False >>> |
(5)q.full() 如果队列满了,返回True,反之False
1 2 3 | >>> que.full() False >>> |
q.full 与 maxsize 大小对应
其他方法:
1 2 3 4 5 6 | q.get([block[, timeout]]) 获取队列,timeout等待时间 q.get_nowait() 相当q.get( False ) 非阻塞 q.put(item) 写入队列,timeout等待时间 q.put_nowait(item) 相当q.put(item, False ) q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号 q.join() 实际上意味着等到队列为空,再执行别的操作 |
三.深浅拷贝
1.为什么要拷贝?
当进行修改时,想要保留原来的数据和修改后的数据
2.数字字符串 和 集合 在修改时的差异? (深浅拷贝不同的终极原因)
在修改数据时:
数字字符串:在内存中新建一份数据
集合:修改内存中的同一份数据
3.对于集合,如何保留其修改前和修改后的数据?
在内存中拷贝
深拷贝
1.对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 赋值,内存指向同一地址 >>> n1= 123 >>> n2=n1 >>> id(n1) 10109728 >>> id(n2) 10109728 >>> >>> import copy >>> n3 = copy.copy(n1) >>> id(n3) 10109728 >>> n4=copy.deepcopy(n1) >>> id(n4) 10109728 >>> |
2.对于字典、元祖、列表 而言,进行赋值、浅拷贝和深拷贝时,其内存地址的变化是不同的。
赋值,只是创建一个变量,该变量指向原来内存地址,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | >>> import copy >>> n1 = { 'k1' : 'v1' , 'k2' : 'v2' , 'k3' :[ 'liuyao' , 'job' ]} >>> n1 { 'k3' : [ 'liuyao' , 'job' ], 'k1' : 'v1' , 'k2' : 'v2' } >>> n2 = n1 >>> id (n1) 140120750514696 >>> id (n2) 140120750514696 >>> id (n2[ 'k3' ]) 140120750335688 >>> id (n1[ 'k3' ]) 140120750335688 >>> id (n1[ 'k3' ][ 0 ]) 140120778934064 >>> id (n2[ 'k3' ][ 0 ]) 140120778934064 >>> |
(3)浅拷贝,在内存中只额外创建第一层数据
1 2 3 4 5 6 7 8 9 10 11 12 | >>> import copy >>> n1 = { 'k1' : 'v1' , 'k2' : 'v2' , 'k3' :[ 'liuyao' , 'job' ]} >>> n2 = copy.copy(n1) >>> id (n1) 140120750337544 >>> id (n2) 140120750371208 >>> id (n1[ 'k3' ][ 0 ]) 140120778934064 >>> id (n2[ 'k3' ][ 0 ]) 140120778934064 >>> |
(4)深拷贝,在内存中将所有的数据重新创建一份(排除最后一层,即:python内部对字符串和数字的优化)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> import copy >>> n1 = { 'k1' : 'v1' , 'k2' : 'v2' , 'k3' :[ 'liuyao' , 'job' ]} >>> n2 = copy.deepcopy(n1) >>> id (n1) 140120750514696 >>> id (n2) 140120750514888 >>> id (n1[ 'k3' ]) 140120750335688 >>> id (n2[ 'k3' ]) 140120750335752 >>> id (n2[ 'k3' ][ 0 ]) 140120778934064 >>> id (n1[ 'k3' ][ 0 ]) 140120778934064 >>> |
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #深浅copy案例:监控模板 dic = { "cpu" :[ 80 ,], "mem" :[ 70 ,], "disk" :[ 90 ,], } print(dic) a1=copy.copy(dic) #浅copy会使所有的模板cpu都发生变化 a1[ 'cpu' ][ 0 ]= 20 print(a1) print(dic) #为了防止新模板修改导致旧模板被修改所以使用深copy a2=copy.deepcopy(dic) a2[ 'cpu' ][ 0 ]= 20 print(a2) print(dic) |