06--基本类型03:集合 和字符编码

1.集合

见https://zhuanlan.zhihu.com/p/108793771

1.1 介绍

# 1.作用
集合、list、tuple、dict一样都可以存放多个值,但是集合主要用于:去重、关系运算


# 2.定义
"""
定义:在{}内用逗号分隔开多个元素,集合具备以下三个特点:
     1:每个元素必须是不可变类型
     2:集合内没有重复的元素
     3:集合内元素无序
"""
s = {1,2,3,4}   # 本质 s = set({1,2,3,4})

# 注意
  1.列表类型是索引对应值,字典是key对应值,均可以取得单个指定的值,
  而集合类型既没有索引也没有key与值对应,所以无法取得单个的值,
  而且对于集合来说,主要用于去重与关系元素,根本没有取出单个指定值这种需求。

  2.{}既可以用于定义dict,也可以用于定义集合,但是字典内的元素必须是key:value的格式,
    现在我们想定义一个空字典和空集合,该如何准确去定义两者?
    d = {}  # 默认是空字典 
    s = set() # 这才是定义空集合

    
# 3.类型转换
  但凡能被for循环的遍历的数据类型(强调:遍历出的每一个值都必须为不可变类型)都可以传给set()转换成集合类型

s = set([1,2,3,4])  # {1, 2, 3, 4}
s1 = set((1,2,3,4))  #  {1, 2, 3, 4} 
s2 = set({'name':'jason',})  # {'name'}
s3 = set('egon')  # {'e', 'o', 'g', 'n'}

1.2 使用

### 关系运算

friends1 = {"zero","kevin","jason","egon"}  # 用户1的好友们 
friends2 = {"Jy","ricky","jason","egon"}   # 用户2的好友们

# 1.合集/并集(|):求两个用户所有的好友(重复好友只留一个)
friends1 | friends2
{'kevin', 'ricky', 'zero', 'jason', 'Jy', 'egon'}

# 2.交集(&):求两个用户的共同好友
friends1 & friends2
{'jason', 'egon'}

# 3.差集(-):
friends1 - friends2  # 求用户1独有的好友
{'kevin', 'zero'}
friends2 - friends1  # 求用户2独有的好友
{'ricky', 'Jy'}

# 4.对称差集(^) # 求两个用户独有的好友们(即去掉共有的好友)
friends1 ^ friends2
{'kevin', 'zero', 'ricky', 'Jy'}

# 5.值是否相等(==)
friends1 == friends2
False

# 6.父集:一个集合是否包含另外一个集合
# 6.1 包含则返回True
{1,2,3} > {1,2}
True
{1,2,3} >= {1,2}
True
# 6.2 不存在包含关系,则返回False
{1,2,3} > {1,3,4,5}
False
{1,2,3} >= {1,3,4,5}
False


# 7.子集
{1,2} < {1,2,3}
True
{1,2} <= {1,2,3}
True


### 去重

# 集合去重复有局限性
  1. 只能针对不可变类型
  2. 集合本身是无序的,去重之后无法保留原来的顺序

l=['a','b',1,'a','a']
s=set(l)   # 将列表转成了集合
{'b', 'a', 1}

l_new=list(s)  # 再将集合转回列表
['b', 'a', 1]  # 去除了重复,但是打乱了顺序


# 针对不可变类型,并且保证顺序则需要我们自己写代码实现,例如
l=[
    {'name':'lili','age':18,'sex':'male'},
    {'name':'jack','age':73,'sex':'male'},
    {'name':'tom','age':20,'sex':'female'},
    {'name':'lili','age':18,'sex':'male'},
    {'name':'lili','age':18,'sex':'male'},
]

new_l=[]

for dic in l:
    if dic not in new_l:
        new_l.append(dic)

print(new_l)
# 结果:既去除了重复,又保证了顺序,而且是针对不可变类型的去重
[
    {'age': 18, 'sex': 'male', 'name': 'lili'}, 
    {'age': 73, 'sex': 'male', 'name': 'jack'}, 
    {'age': 20, 'sex': 'female', 'name': 'tom'}
]

1.3 其他方法

# 1.长度
s={'a','b','c'}
len(s)  # 3

# 2.成员运算
'c' in s  # True

# 3.循环
for item in s:
	print(item)

c
a
b

2.字符编码

字符编码表就是一张字符与数字的对应关系的表

2.1 发展史

# 阶段一:一家独大---》ASCII表 
    1.只支持英文字符串
    2.一个英文字符对应1Bytes,1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符
  

# 阶段二:诸侯割据----》各国各自标准 
    1.中国人定制了GBK
    
    # GBK表的特点:
        1、只有中文字符、英文字符与数字的一一对应关系
        2、一个英文字符对应1Bytes; 一个中文字符对应2Bytes   
        补充说明:
            1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符
            2Bytes=16bit,16bit最多包含65536个数字,可以对应65536个字符,足够表示所有中文字符
     
    
# 阶段三:分久比合----》统一标准 Unicode
    内存中统一使用Unicode编码
    
    # 1.存在所有语言中的所有字符与数字的一一对应关系,即兼容万国字符
        
    # 2.与传统的字符编码的二进制数都有对应关系
    
    	但是由于历史遗留问题,还有许多其他各自编码组成的文件信息等需要保存。(且保存在硬盘上)
	# 此处需要强调:
        软件是存放于硬盘的,而运行软件是要将软件加载到内存的,
        面对硬盘中存放的各种传统编码的软件,在内存读取硬盘数据时,
        该Unicode编码需要与其他编码有相对应的映射/转换关系
       
    
    # UTF-8(Unicode Transformation Format)
	UTF-8是针对Unicode的一种可变长度字符编码

        一个英文字符占1Bytes;一个中文字符占3Bytes,生僻字用更多的Bytes存储

        为节省内存空间,与IO读取速度,将内存中的unicode二进制写入硬盘
        或者基于网络传输时必须将其转换成一种精简的格式,即utf-8

注意:各自老的字符编码都可以转成Unicode,但是不能通过Unicode互转**

# 例:GBK(中文): “哈”------>Unicode------> '00' 二进制
#       二进制:'00'------->Unicode-----> 'かんとう' Shift_JIS(日文)
# 但是转成的日文字符'かんとう',就不一定是中文字符 '哈'的意思了。

因为GBK 和 Shift_JIS 各自和 Unicode 之间的转换关系并不一样,
虽然有对应转换,但是意思就可能不同,就会出现乱码(虽然出现日文或汉字,但是看不懂)

2.2 编码结论

# 1.内存固定使用Unicode,但是我们选择改变的是存入硬盘的编码格式(GBK ,Shift_JIS等)

# 2.文本文件存取乱码问题(内容是什么,就存/取什么格式,最好 'utf-8')

# 3.python解释器默认读文件的编码

    python2 默认:ASCII  读文件
    python3 默认:utf-8  读文件

2.3 防止出现乱码

# 1.运行python程序(读py文件,并执行)前两个阶段不乱码的核心法则:
    执行py文件的前两个阶段就是python解释器读py文件的过程,与文本编辑读文本文件的前两个阶段没人任何区别

    """
    若以指定编码存的文件内容,就以同样编码的读文件。
    方式:指定文件头修改默认的编码  (主要针对python2,因为解释器默认是ASCII读取)
      # coding :编码 (在py文件的首行写)---》但本行内容(英文),是以解释器默认编码读取的。
    """

# 2.运行python程序第三个阶段不乱码的核心法则:
    运行第三个阶段时开始识别python语法(经过前两个阶段后py文件的内容都会以unicode格式存放于内存中)
    
    python3 无需操作 -----> 解释器,本身底层就是Unicode在内存中存储str
    python2 将字符串前加u:x = u'你好'
        解释:表明内存中执行这行代码时,申请内存空间时 强行以Unicode 存储字符串'你好',并指向变量x



# 了解:
python2中,字符串实际是两种类型:
    1. 纯字符串类型:'你好' 
    ---->在第三阶段识别语法时,赋值操作会在内存申请空间时,会以文件头中的编码去存储二进制。
    ---->注:文件头的编码肯定是支持'你好'的编码,不然就和没有文件头一样(解释器默认编码 ASCII)
    	直接出现了 前两个阶段的 乱码问题,都到不了识别语法的这个阶段(第三阶段)。

    2. Unicode类型字符串:u'你好'
    ---->在第三阶段识别语法时,赋值操作会在内存申请空间时,强制以Unicode编码去存储二进制。


# 总结:
    python3  不用管(文件存取都是utf-8,字符串是Unicode)
    python2  指定文件头,字符串前加 u
posted @ 2022-06-09 09:17  Edmond辉仔  阅读(41)  评论(0)    收藏  举报