本文章内容:
dict (创建、生成式、元素获得、判断、删除、新增、视图、遍历),
tuple (创建、元素获得、判断、遍历)
set (创建、生成式、元素获得、判断、删除、新增、遍历、集合间关系、集合间数学操作)
str (驻留机制、查询、大小写,对齐、劈分、判断、替换,比较,切片,格式化字符串,编码解码)
'''
-------------------------------
---------- 字典 dict -----------
-------------------------------
'''
# 字典
# 是python内置的数据结构之一,与列表一样是一个可变序列
# 以键值对的方式存储数据,字典是一个无序的序列
# 字典中所有元素都是一个key-value对,key不允许重复,value可以重复
# 字典中key必须是不可变对象
# 字典可以根据需要动态伸缩
# 字典会浪费较大的内存,是一种使用空间换时间的数据结构
# 字典创建
# 使用{}
d1 = {'张三': 100, '李四': 98, '王五': 45}
# 使用内置函数dict()
d2 = dict(name='jack', age=20)
d3 = {} # 空字典
print(type(d1), d1)
print(type(d2), d2)
print(type(d3), d3)
# 字典生成式
# 内置函数zip()
# 用于将可迭代的对象作为参数,将对象中对应的元素打包成一个元组,然后返回由这些元组组成的列表
items = ['fruits', 'books', 'others']
prices = [96, 78, 85, 100, 120]
lst = zip(items, prices) # <zip object at 0x00000224BBB929C0>
print(list(lst)) # [('fruits', 96), ('books', 78), ('others', 85)]
d = {item: price for item, price in zip(items, prices)}
print(d) # {'fruits': 96, 'books': 78, 'others': 85}
# 字典元素获取
# [] d['张三']
# 如果字典中不存在指定的key,抛出keyError异常
d = {'张三': 100, '李四': 80, '王五': 45}
print(d['张三'])
# print(d['陈六']) # KeyError: '陈六'
# get()方法
# 如果字典中不存在指定的key,并不会抛出keyError而是返回None
# 可以通过参数设置默认的value,以便指定的key不存在时返回
print(d.get('张三'))
print(d.get('陈六')) # None
print(d.get('马奇', 99)) # 99
# key 的判断
# in/not in
print('张三' in d) # True
print('张三' not in d) # False
# 字典元素删除
del d['张三']
print(d)
# 字典元素清空
d.clear()
print(d)
# 字典元素新增
d['Jack'] = 90
print(d)
d['Jack'] = 100
print(d)
# 字典视图
# keys() 获取字典中所有的key
# values() 获取字典中所有的value
# items() 获取字典中所有的key/value对
d = {'张三': 100, '李四': 80, '王五': 45}
k = d.keys()
print(k, type(k))
print(list(k)) # 将所有的key组成的视图转成列表
v = d.values()
print(v, type(v))
print(list(v)) # 将所有的value组成的视图转成列表
i = d.items()
print(i, type(i))
print(list(i)) # 将所有的字典元素组成的视图转成列表,元组为列表元素
# 字典元素的遍历
# for item in dict:
# ....code
d = {'张三': 100, '李四': 89, '王五': 80}
for item in d:
print(item, d[item], d.get(item))
# 张三 100 100 # dict key
# 李四 89 89
# 王五 80 80
for item in d.items():
print(item)
# ('张三', 100) # tuple
# ('李四', 89)
# ('王五', 80)
for key in d.keys():
print(key)
# 张三
# 李四
# 王五
for value in d.values():
print(value)
# 100
# 89
# 80
for key, value in d.items():
print(key, value)
# 张三 100
# 李四 89
# 王五 80
# key 不能重复。重复则出现value覆盖的情况
d = {'alice': 100, 'tom': 90, 'alice':80}
print(d) # {'alice': 80, 'tom': 90}
# value 可以重复
d = {'alice': 100, 'tom': 90, 'thomas': 100}
print(d) # {'alice': 100, 'tom': 90, 'thomas': 100}
# 字典中key必须是不可变对象
lst = [10, 20, 30]
lst.insert(1, 40)
print(lst)
d = {lst: 22} # TypeError: unhashable type: 'list'
'''
-------------------------------
---------- 元组 tuple ----------
-------------------------------
'''
# 元组
# 元组是python内置的数据结构之一,是一个不可变序列
# 不可变序列 str tuple,没有增删改的操作
# 可变序列 list dict,可执行增删改操作,对象地址不发生更改
lst = [10, 20, 45]
print(id(lst), lst) # 2435163272384
lst.append(300)
print(id(lst), lst) # 2435163272384
s = 'hello'
print(id(s)) # 2435163208496
s = s + 'world'
print(id(s)) # 2435163568368
# 元组创建
# 直接小括号
t = ('python', 'hello', 98)
print(t)
print(type(t))
# 使用内置函数tuple()
t1 = tuple(('python', 'world', 89))
print(t1)
print(type(t1))
# 只包含一个元素的元组需要使用 逗号和小括号
t2 = ('python',)
print(t2)
print(type(t2))
# 空元组
lst = []
lst1 = list()
print(lst, lst1) # 空列表
di = {}
di1 = dict()
print(di, di1) # 空字典
t = ()
t1 = tuple()
print(t, t1) # 空元组
'''
为什么要将元组设计成不可变序列?
1. 在多任务环境下,同时操作对象时不需要加锁
2. 因此,在程序中尽量使用不可变序列
注意:元组中存储的是对象的引用
1)如果元组中的对象本身是不可变对象,则不能再引用其他对象
2)如果元组中的对象本身是可变对象,则可变对象的引用不允许改变,但数据可以改变
'''
t = (10, [20, 30], 9)
print(t)
print(t[0], type(t[0]), id(t[0]))
print(t[1], type(t[1]), id(t[1]))
print(t[2], type(t[2]), id(t[2]))
# t[1] = 100 # tuples don't support item assignment
t[1][0] = 100
t[1].append(100)
print(t[1], type(t[1]), id(t[1]))
# 元组遍历
t = ('python', 'world', 98)
print(t[0])
print(t[1])
print(t[2])
# print(t[3]) # IndexError: tuple index out of range
for i in t:
print(i)
'''
-------------------------------
----------- 集合 set -----------
-------------------------------
'''
# 集合是python语言提供的内置数据结构
# 与列表、字典一样都属于可变类型的序列
# 集合是没有value的字典
# 集合中元素是无序的,不允许重复
# 集合创建
# 1. {}
s = {'python', 'hello', 90, 90} # 集合中元素不允许重复, 如重复会合并
print(s)
# 2. 使用内置函数set()
s1 = set(range(6))
print(s1, type(s1))
# 3. 集合生成式
'''没有元组生成式,因为元组是不可变序列'''
# {i for i in range(5)}
s = {i*i for i in range(10)}
print(s)
# 将列表转换成集合,并处理重复元素
s2 = [3, 4, 5, 53, 5]
print(set(s2)) # {53, 3, 4, 5}
# 将元组转换成集合,并处理重复元素
s3 = (3, 4, 43, 3, 435)
print(set(s3)) # {43, 3, 4, 435}
# 将字符串序列转换成集合
s4 = set('python')
print(s4) # {'p', 'n', 'h', 'o', 't', 'y'}
# 将集合转换成集合,并处理重复元素
s5 = {124, 3, 4, 4, 5}
print(set(s5)) # {4, 3, 124, 5}
# 空集合
# s6 = {} # 会生成一个空字典
s6 = set()
print(s6)
# 集合元素的判断
s = {10, 20, 30, 405, 60}
print(10 in s) # True
print(20 not in s) # False
# 集合元素的新增
# 1. add()方法,一次添加一个元素
s.add(80)
print(s)
# 2. update()方法,至少添加一个元素
s.update({200, 400, 300}) # 添加集合
s.update([100, 8, 89]) # 添加列表
s.update((56, 64, 78)) # 添加元组
print(s)
# 集合元素的删除
# 1. remove()方法,一次删除一个指定元素,如指定元素不存在抛出KeyError
s.remove(10)
print(s)
# s.remove(500) # KeyError: 500
# 2. discard()方法,一次删除一个指定元素,如指定元素不存在不抛异常
s.discard(500)
print(s)
# 3. pop()方法,一次只删除一个任意元素
s.pop()
s.pop()
print(s)
# 4. clear()方法,清空集合
s.clear()
print(s)
# 集合间的关系
# 1. 相等---元素相同就相等
s1 = {10, 20, 30, 405, 60}
s2 = {10, 20, 405, 60, 30}
print(s1 == s2) # True
# 2. 子集
s11 = {10, 20, 30, 405, 60}
s21 = {10, 20, 405, 60}
s31 = {10, 20, 90}
s41 = {100, 200, 900}
print(s21.issubset(s11)) # True
print(s31.issubset(s11)) # False
# 3. 超集
print(s11.issuperset(s21)) # True
print(s11.issuperset(s31)) # False
# 4. 是否交集
print(s21.isdisjoint(s31)) # False
print(s21.isdisjoint(s41)) # True
# 集合的数学操作
# 1. 交集---intersection() 与 & 等价
sj1 = {10, 20, 30, 40}
sj2 = {20, 30, 40, 50, 60}
print(sj1.intersection(sj2))
print(sj1 & sj2)
print(sj1) # sj1 没变
print(sj2) # sj2 没变
# 2. 并集---union() 与 | 等价
print(sj1.union(sj2))
print(sj1 | sj2)
print(sj1) # sj1 没变
print(sj2) # sj2 没变
# 3. 差集---difference() 与 - 等价
print(sj1.difference(sj2))
print(sj1 - sj2)
# 4. 对称差集---symmetric_difference() 与 ^ 等价
print(sj1.symmetric_difference(sj2))
print(sj1 ^ sj2)
'''---------------------- 总结 ----------------------
数据结构 是否可变 是否重复 是否有序 定义符号
列表list | 可变 | 可重复 | 有序 | []
元组tuple | 不可变 | 可重复 | 有序 | ()
字典dict | 可变 | key不可,value可 | 无序 | {key:value}
集合set | 可变 | 不可重复 | 无序 | {}
--------------------------------------------------'''
'''
-------------------------------
----------- 字符串 str ---------
-------------------------------
'''
# 在python中字符串是基本的数据类型,是一个不可变的字符序列
"""
字符串驻留机制:仅保存一份相同且不可变字符串的方法,不同的值被
存放在字符串的驻留池中.
python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,
不会开辟新空间,而是把该字符串的地址赋给新创建的变量.
"""
s = "python"
s1 = 'python'
s2 = """python"""
print(s, id(s)) # python 2654294882992
print(s1, id(s1)) # 同上
print(s2, id(s2)) # 同上
# 驻留机制的几种情况(交互模式)
# 1. 字符串的长度为0或1时
# 2. 符合标识符的字符串
# 3. 字符串只在编译时进行驻留,而非运行时
# 4. [-5, 256]之间的整数数字
# sys.intern()方法强制2个字符串指向同一个对象
# pycharm对字符串进行了优化处理
# 例子(交互模式)
'''字符串的长度为0'''
# >>> s1 = ''
# >>> s2 = ''
# >>> s1 is s2 # True
'''字符串的长度为1'''
# >>> s1 = '%'
# >>> s2 = '%'
# >>> s1 is s2 # True
'''不符合标识符的字符串'''
# >>> s1 = 'abc%'
# >>> s2 = 'abc%'
# >>> s1 == s2 # True
# >>> s1 is s2 # False
# >>> id(s1) # 2965443062128
# >>> id(s2) # 2965443065968
'''符合标识符的字符串'''
# >>> s1 = 'abcx'
# >>> s2 = 'abcx'
# >>> s1 == s2 # True
# >>> s1 is s2 # True
'''字符串只在编译时进行驻留,而非运行时'''
# >>> a = 'abc'
# >>> b = 'ab' + 'c' # 编译时得到b值
# >>> c = ''.join(['ab', 'c']) # 运行时才能得到c值
# >>> a is b # True
# >>> a is c # False
'''[-5, 256]之间的整数数字'''
# >>> a = -5
# >>> a = -5
# >>> a is b # True
# >>> a = -6
# >>> a = -6
# >>> a is b # False
'''sys.intern()方法强制2个字符串指向同一个对象'''
# >>> s1 = 'abc%'
# >>> s2 = 'abc%'
# >>> s1 is s2 # False
# >>> import sys
# >>> s1 = 'abc%'
# >>> s2 = 'abc%'
# >>> s1 is s2 # False
# >>> s2 = sys.intern(s1)
# >>> s1 is s2 # True
'''pycharm对字符串优化'''
'''不符合标识符的字符串'''
# s1 = 'abc%'
# s2 = 'abc%'
# print(s1 is s2) # True
'''
字符串驻留机制的优缺点:
1. 当需要值相同的字符串时,可以直接从字符串池里拿来使用,避免频繁
的创建和销毁,提升效率和节约内存,因为拼接字符串和修改字符串是
比较影响性能的
2. 在需要进行字符串拼接时建议使用 str 类型的 join()方法,而非 +,
因为 join() 方法是先计算出所有字符串的长度,然后再拷贝,只 new
一次对象,效率要比 + 效率高
'''
# 字符串查询
# index() 查找子串substr第一次出现的位置,如果查找的子串不存在,抛出ValueError
# rindex() 查找子串substr最后一次出现的位置,如果查找的子串不存在,抛出ValueError
# find() 查找子串substr第一次出现的位置,如果查找的子串不存在,返回-1
# rfind() 查找子串substr最后一次出现的位置,如果查找的子串不存在,返回-1
s = 'hello,hello'
print(s.index('lo'))
print(s.rindex('lo'))
print(s.find('k'))
print(s.rfind('k'))
# 字符串大小写
# upper() 所有字符转成大写,会生成一个新的字符串对象
# lower() 所有字符转成小写, 会生成一个新的字符串对象
# swapcase() 所有大写转成小写,小写转成大写
# capitalize() 把第一个字符转成大写,其余转成小写
# title() 把每个单词的第一个字符转成大写,把每个单词其余字符转成小写
# 字符串内容对齐
# center() 居中对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数是可选的,
# 默认是空格,如果设置宽度小于实际宽度则返回原字符串
# ljust() 左对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数是可选的,
# 默认是空格,如果设置宽度小于实际宽度则返回原字符串
# rjust() 右对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数是可选的,
# 默认是空格,如果设置宽度小于实际宽度则返回原字符串
# zfill() 右对齐,左边用0填充,该方法只接收一个参数,用于指定字符串的宽度,如果指定
# 的宽度小于等于字符串的长度,返回字符串本身
s = 'hello,Python'
print(s.center(20, '*')) # ****hello,Python****
print(s.ljust(20, '*')) # hello,Python********
print(s.rjust(20, '*')) # ********hello,Python
print(s.zfill(20)) # 00000000hello,Python
# 字符串劈分
# split() 从字符串左边开始劈分,默认的劈分字符是空格,返回的值是一个列表
# 参数 sep 指定劈分字符串的劈分符
# 参数 maxsplit 指定劈分字符串时的最大劈分次数,在经过最大次劈分后,剩余的子串会单独做为一部分
# rsplit() 从字符串的右边开始劈分,默认的劈分字符的是空格,返回的值是一个列表
# 参数 sep 指定劈分字符串的劈分符
# 参数 maxsplit 指定劈分字符串时的最大劈分次数,在经过最大次劈分后,剩余的子串会单独做为一部分
s = 'hello world python'
lst = s.split()
print(lst) # ['hello', 'world', 'python']
s1 = 'hello|world|python'
lst1 = s1.split(sep='|')
print(lst1) # ['hello', 'world', 'python']
lst2 = s1.split(sep='|', maxsplit=1)
print(lst2) # ['hello', 'world|python']
lst3 = s1.rsplit(sep='|', maxsplit=1)
print(lst3) # ['hello|world', 'python']
# 字符串判断
# isidentifier() 是否合法的标识符
# isspace() 是否全部由空白字符组成(回车、换行、水平制表符)
# isalpha() 是否全部由字母组成
# isdecimal() 是否全部由十进制数字组成
# isnumeric() 是否全部由数字组成
# isalnum() 是否全部由字母和数字组成
s = 'hello.python'
print(s.isidentifier())
print('2.', 'hello'.isidentifier())
print('3.', '张三_'.isidentifier())
print('\t'.isspace())
print('123'.isdecimal())
# replace() 字符串替换
# 第一个参数指定被替换的子串,第二个参数指定替换子串的字符串,返回替换后得到的字符串
# 替换前的字符串不发生变化。调用该方法可以通过第三个参数指定最大替换次数
# join() 字符串合并
# 将列表或元组中的字符串合并成一个字符串
s1 = 'hello python'
s2 = 'c++'
print(s1.replace('python', s2)) # hello c++
s1 = 'hello python python python'
s2 = 'c++'
print(s1.replace('python', s2, 2)) # hello c++ c++ python
lst = ['hello', 'python', 'alice']
print('|'.join(lst)) # hello|python|alice
print(''.join(lst)) # hellopythonalice
print('*'.join('python')) # p*y*t*h*o*n, 将str看成一个序列
# 字符串比较
# > < >= <= == !=
# 比较规则:首先比较两个字符串的第一个字符,如果相等则继续比较下一个,依次比较下去
# 比较原理:两个字符进行比较时,比较的是其ordinal value(原始值)
# 调用内置函数ord()可以得到指定字符的ordinal value。
# 对应的内置函数chr(),可以得到指定ordinal value 对应的字符
print('apple' > 'app') # True
print('apple' > 'banana') # False
print(ord('a'), ord('c')) # 97 99
print(chr(97), chr(98)) # a b
print(ord('刘'))
print(chr(21016))
# 字符串切片
# 切片操作将产生新的对象
s = 'hello,python'
s1 = s[:5]
s2 = s[6:]
print(s1, id(s1))
print(s2, id(s2))
s3 = s1 + '!' + s2
print(s3, id(s3))
print(s[::2]) # hlopto
print(s[::-1]) # nohtyp,olleh
print(s[-6::]) # python
# 格式化字符串
# %做占位符 %s-字符串, %i或%d-整数, %f-浮点数
name = '张三'
age = 20
print('我叫%s,今年%d岁' % (name, age))
# {}做占位符
print('我叫{0},今年{1}岁'.format(name, age))
# f-string
print(f'我叫{name},今年{age}岁')
print('%10d' % 99) # 10表示的是宽度
print('%.3f' % 3.1415926) # .3表示小数点后三位
print('%10.3f' % 3.1415926) # 总宽度10,小数点后三位
print('{0:.3}'.format(3.1415926)) # 3.14
print('{0:.3f}'.format(3.1415926)) # 3.142
print('{0:10.3f}'.format(3.1415926)) # 3.142 总宽度10,小数点后三位
# 字符串编码解码
# GBK这种编码中 一个中文占两个字节
# UTF-8这种编码中 一个中文占三个字节
s = '天涯共此时'
print(s.encode(encoding='GBK')) # b'\xcc\xec\xd1\xc4\xb9\xb2\xb4\xcb\xca\xb1'
print(s.encode(encoding='UTF-8')) # b'\xe5\xa4\xa9\xe6\xb6\xaf\xe5\x85\xb1\xe6\xad\xa4\xe6\x97\xb6'
byte = b'\xcc\xec\xd1\xc4\xb9\xb2\xb4\xcb\xca\xb1'
print(byte.decode(encoding='GBK'))
byte = b'\xe5\xa4\xa9\xe6\xb6\xaf\xe5\x85\xb1\xe6\xad\xa4\xe6\x97\xb6'
print(byte.decode(encoding='UTF-8'))