python基础四(集合、深浅拷贝)

时间:2021-03-18 19:49:42

八)集合

1、集合的概述

集合是一个无序、不重复的数据组合,只有可哈希的对象才可以被添加进集合(不可变类型:字符串、数字、元组、不可变集合)

主要的作用如下:

1)去重,把一个列表变成集合就去重了

2)关系测试,测试两组数据间的交集、并集、差集等

li=[1,2,'a','b']
s =set(li)
print(s)    
>>{1, 2, 'a', 'b'}
 
li2=[1,2,1,'a','a']
s=set(li2)
print(s)  
>>{1, 2, 'a'} 

2、注意的问题

集合对象是一组无序排列的可哈希的对象:集合成员可以做字典的键 

li=[[1,2],'a','b']#集合的成员必须是不可变的
s =set(li) 
print(s)
>>TypeError: unhashable type: 'list'

set1 = {1, 3, 3, 4, 'mjc'}
dict1 = {x:x*4 for x in set1} #集合的成员可以作字典的键
print(dict1)
>>{1: 4, 'mjc': 'mjcmjcmjcmjc', 3: 12, 4: 16}
集合的分类:可变集合和不可变集合

可变集合(set):可添加和删除元素,非可哈希的,不能用作字典的键,也不能做其他集合的元素

li=[1,'a','b']
s =set(li)
dic={s:'123'} #注意这里是整个集合作为字典的键,因为可变,所以不能作为字典的键
>>TypeError: unhashable type: 'set' 

 3、集合的相关操作

1)创建集合

由于集合没有自己的语法格式,只能通过集合的工厂方法set()和frozenset()创建

s1 = set('alvin')
s2= frozenset('yuan')
print(s1,type(s1)) 
>>{'l', 'v', 'i', 'a', 'n'} <class 'set'>
print(s2,type(s2)) 
>>frozenset({'n', 'y', 'a', 'u'}) <class 'frozenset'> 

2)访问集合

由于集合本身是无序的,所以不能为集合创建索引或切片操作,只能循环遍历或使用in、not in来访问或判断集合元素。

s1 = set('alvin')
print('a' in s1)
>>True
print('b' in s1)
>>False
print('alvin' in s1)
>>Fale
s1[1]  
>>TypeError: 'set' object does not support indexing
for i in s1:
    print(i)
>>v
 n
 l
 i
 a

3)更新集合

可使用以下内建方法来更新:

s.add()
s.update()
s.remove() 删除不存在的会报错

s.discard() 删除不存在的不会报错

注意只有可变集合才能更新:

s1 = frozenset('alvin')
s1.add(0)  
>>AttributeError: 'frozenset' object has no attribute 'add'
 
s2=set('alvin')
s2.add('mm')
print(s2)  
>>{'mm', 'l', 'n', 'a', 'i', 'v'}
s2.update('HO')#添加多个元素
print(s2)  
>>{'mm', 'l', 'n', 'a', 'i', 'H', 'O', 'v'}
s2.remove('l')
print(s2)  
>>{'mm', 'n', 'a', 'i', 'H', 'O', 'v'}

del:删除集合本身 

 

4、集合类型操作符

1) in ,not in

2)  集合等价与不等价(==, !=)

3)子集、超集

s=set('alvinyuan')
s1=set('alvin')
print('v' in s)
>>True
print(s1<s)
>>True

4)并集

(|)union()

a = set([1, 2, 3, 4, 5])
b = set([4, 5, 6, 7, 8])
# 并集 '|' ,union() a和b去重后所有的
print(a.union(b))
print(a | b)
>>{1, 2, 3, 4, 5, 6, 7, 8}
>>{1, 2, 3, 4, 5, 6, 7, 8}

5)交集

(&)intersection()

a = set([1, 2, 3, 4, 5])
b = set([4, 5, 6, 7, 8])
# 交集 (&) intersection() a和b都有的
print(a.intersection(b))
print(a & b)
>>{4, 5}
>>{4, 5}

6)差集

(-)difference()

a = set([1, 2, 3, 4, 5])
b = set([4, 5, 6, 7, 8])
# 差集 (-) difference() a有b没有的
print(a.difference(b))
print(a - b)
>>{1, 2, 3}
>>{1, 2, 3}

7)对称差集

(^)symmetric_difference()

a = set([1, 2, 3, 4, 5])
b = set([4, 5, 6, 7, 8])
# 对称差集 (-) symmetric_difference()a和b的反向交集
print(a.symmetric_difference(b))
print(a ^ b)
>>{1, 2, 3, 6, 7, 8}
>>{1, 2, 3, 6, 7, 8}

(九)深浅拷贝

1、数字和字符串

对于字符串和数字,赋值和浅拷贝,深拷贝毫无意义,因为同时指向的是同一个内存地址

import copy

############# 数字和字符串 ##############
n1 = 123
n2 = 'mjc'
n1_1 = n1 # 赋值
n2_2 = n2 # 赋值
print(id(n1), id(n1_1))
>>4355288240 4355288240
print(id(n2), id(n2_2))
>>4358346040 4358346040
n1_c = copy.copy(n1) # 浅拷贝
n2_c = copy.copy(n2) # 浅拷贝
print(id(n1), id(n1_c), id(n2), id(n2_c))
>>4355288240 4355288240 4358346040 4358346040
n1_d = copy.deepcopy(n1) # 深拷贝
n2_d = copy.deepcopy(n2) # 深拷贝
print(id(n1_d), id(n1), id(n2_d), id(n2))
>>4355288240 4355288240 4358346040 4358346040

python基础四(集合、深浅拷贝)

2、其他数据类型

对于字典、元祖、列表 而言,进行赋值、浅拷贝和深拷贝时,其内存地址的变化是不同的。

 

 (1)赋值

赋值,只是创建一个变量,该变量指向原来内存地址,如

n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n2 = n1

python基础四(集合、深浅拷贝)

(2)浅拷贝

浅拷贝,在内存中只额外创建第一层数据

 import copy
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n3 = copy.copy(n1)

python基础四(集合、深浅拷贝)

(3)深拷贝

深拷贝,在内存中将所有的数据重新创建一份(排除最后一层,即:python内部对字符串和数字的优化)

import copy
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n4 = copy.deepcopy(n1)

python基础四(集合、深浅拷贝)

列表和字典循环删除的问题

列表在循环的时候如果执行了删除操作. 索引和长度会有变化. 这种删除是不安全.
先把要删除的内容放在一个新列表中. 然后循环这个新列表. 删除老列表.

# lst = ["倚天屠龙记", "诛仙", "看见", "追风筝的人"]
# clear()
# lst.clear()
# print(lst)
# 有问题
# for i in lst:
#     lst.remove(i)
# print(lst)

# for i in lst:# for在这里的意义是记录删除的次数
#     del lst[0] # 不正确
# print(lst)



lst = ["倚天屠龙记", "诛仙", "看见", "追风筝的人"]

# 正确
# for i in range(0, len(lst)):
#     lst.pop()
# print(lst)

# # 把要删除的东西保存在一个新列表中
# new_lst = []
# for el in lst:
#     new_lst.append(el)
# # 循环新列表. 删除老列表
# for e in new_lst:
#     lst.remove(e)
# print(lst)

dict在循环过程中是不允许删除的.
把要删除的键放在列表中. 循环列表删除字典

# #  生成出来的键指向的value是同一个对象. 改变其中一个的时候. 另一个也会跟着改变
# # dic = dict.fromkeys(["jay", "jj"], ["周杰伦", "林俊杰"])
# # dic['jay'].append("蔡依林")
# # print(dic)
#
# # dic = {}
# # dic.fromkeys(["葫芦娃", "蛇精"], ["冯提莫", "陈一发"])
# # print(dic) # 什么都不打印.
#
# # dic = {"韩哥":"发图不留种", "奎峰":"斗图小皇帝", "徐阳":"开车不留情"}
# # for item in dic: # 直接循环迭代的时候拿到的是key
# #     if item == '奎峰':
# #         dic.pop(item)   # dictionary changed size during iteration
#
# # 循环删除的案例
# # dic = {"韩哥":"发图不留种", "奎峰":"斗图小皇帝", "徐阳":"开车不留情"}
# # lst = ['奎峰']
# # for el in lst:  # 循环list
# #     dic.pop(el) # 删除的是dict中的元素
# # print(dic)
#
# lst = ["发图哥", "谁困. 下午就往他那发图", "轰炸"]
# print(type(lst)) # list
# tu1 = tuple(lst)    # tuple
# print(tu1)  # ()
# print(type(tu1)) # tuple
# lst1 = list(tu1)    # list
# print(lst1) # []
#
# # 能转换成False的数据类型有哪些
# # 0, '', [], (), {}, None, set(), False


dic = {"a":'老A', 'b':"王宝强", 'c':"蓉姐", 'd':'百合姐'}

for k in dic:
    if k == 'b' or k == 'c':
        dic.pop(k)  # dictionary changed size during iteration