对内置的常用数据结构, 列表, 字典, 元组, 集合 的基本点看书整理.
有序序列:
- 列表、元组、字符串
无序序列:
- 字典、集合
可变序列:
- 列表、字典、集合
不可变序列:
- 元组、字符串
基本涉及功能:
- 增、删、查、改
列表:升级版数组
特点:
- 支持双向索引
- 包含若干元素的有序连续内存空间,数据增删改时,自动进行内存的扩展或收缩
- 尽量从列表尾部进行元素的追加、删除操作
- Python基于值的自动内存管理,变量存储的是值的内存地址,列表元素也是值的引用,所以列表可以存不同类型的数据
- 列表能增删查改,但同时负担也很重,需根据实际情况选择合适的数据类型,要尽量避免过多使用列表
列表的创建与删除
a_list = [1,3,'abc', 'xyc']
a_list = [] # 创建空列表
list((1,3,5,7,9))
[1, 3, 5, 7, 9]
list(range(1,11,2)) # 将range对象转为列表
[1, 3, 5, 7, 9]
list("hello world") # 将字符串转为列表
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
list({1,3,4,4,5,6,'b'}) # 将集合转为列表
[1, 3, 4, 5, 6, 'b']
list({'a':3, 'b':4, 'c':5}) # 将字典的key转为列表
['a', 'b', 'c']
list({'a':3, 'b':4, 'c':5}.values()) # 将字典的value转为列表
[3, 4, 5]
list({'a':3, 'b':4, 'c':5}.items()) # 将字典的key-value转为列表
[('a', 3), ('b', 4), ('c', 5)]
x = list() # 创建空列表
x = [1,2,3]
del x # 删除列表对象
x
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-14-bcecaca5435f> in <module>()
1 x = [1,2,3]
2 del x # 删除列表对象
----> 3 x
NameError: name 'x' is not defined
列表元素访问
x = list("Python")
x
['P', 'y', 't', 'h', 'o', 'n']
x[0]
'P'
x[-1]
'n'
x[2] # 第3个元素
't'
x[1:3] # 切片,前闭后开,1,2号元素
['P', 'y']
x[-4:-6:-1] # 右边索引,步长要为负数
['t', 'y']
列表常用方法(增删查改)
增:
l.apped(x)
l.insert(index, x)
l.extend(L)
删:
l.remove(x)
l.pop(index) 删除并返回该元素,默认是尾部
l.clear()
del l[index]
** 查**:
l[index]
改:
l[index] = value
append(); insert(); extend()
x = [1,2,3]
id(x) # 查看对象的内存地址
642846558152
x.append(4) # 尾部追加
print(x)
id(x) # 不改变列表内存地址(是同一个对象)
[1, 2, 3, 4]
642846558152
x.insert(3, 'aaa') # 前插,后挪, 消耗大,慎用
x
[1, 2, 3, 'aaa', 4]
x.extend(['bb','cc','dd']) # 尾部追加多个元素
x
[1, 2, 3, 'aaa', 4, 'bb', 'cc', 'dd']
pop(); remove(); clear()
x = [1,2,3,4,5,6,7]
x.pop() # 删除,并弹出尾部元素
7
x.pop(0)
1
x
[2, 3, 4, 5, 6]
x.clear() # 清空所有元素
x
[]
x = [1,2,2,3,4]
x.remove(2) # 删除首个值为2的元素
x
[1, 2, 3, 4]
del x[3] # 删除指定索引的元素
x
[1, 2, 3]
注意: 列表具有内存自动收缩、扩张功能,不适合在中间位置进行元素的增删,而且会改变后面所有元素的索引值
查、改
list[index] = value; l.index(value)
x = [1,2,3,4]
x.index(3) # 返回值首次出现值为3 的index
2
x[2] = 'abc' # 将列表里值为 3 的元素替换为 abc: 1、找到3的索引: list.index(3); 2: list[index] = value
x
[1, 2, 'abc', 4]
count(); index()
x = [1,2,3,3,6,6,5,6,6,4,'aaa']
x.count(6) # 元素 3 在列表中出现的次数
4
x.count(3)
2
x.count('a')
0
x.index(3) # 元素2 在列表中首次出现的index
2
x.index('dfsf') # 没找到则抛出异常
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-65-b1f8470b4d3d> in <module>()
----> 1 x.index('dfsf') # 没找到则抛出异常
ValueError: 'dfsf' is not in list
提示:列表会在很多地方抛出异常,从而导致程序的崩溃,解决方法有两种:
- 用选择结构if-else过滤掉可能会异常的情况
- 用异常处理try - except - else处理异常情况
import random
random.sample([1,3,4,2,4,5,6,4,3,2,],7)
[4, 1, 3, 6, 2, 3, 2]
Signature: random.sample(population, k)
Docstring:
Chooses k unique random elements from a population sequence or set.Returns a new list containing elements from the population while
leaving the original population unchanged. The resulting list is
in selection order so that all sub-slices will also be valid random
samples. This allows raffle winners (the sample) to be partitioned
into grand prize and second place winners (the subslices).Members of the population need not be hashable or unique. If the
population contains repeats, then each occurrence is a possible
selection in the sample.To choose a sample in a range of integers, use range as an argument.
This is especially fast and space efficient for sampling from a
large population: sample(range(10000000), 60)
File: d:\software\anaconda3\lib\random.py
Type: method
assert 1 < 2, print("断言错啦") # 断言正确则会忽略后面的表达式
assert 9 < 5, print("断言错啦") # assert 失败则会返回后面表达式的值, 有点像 if-else
断言错啦
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-77-4b61c3dd7e47> in <module>()
----> 1 assert 9 < 5, print("断言错啦") # assert 失败则会返回后面表达式的值, 有点像 if-else
AssertionError: None
lst = random.sample(range(100, 1000), 100) # 从100-999里选出100个数字,组成列表
while True:
x = input("请输入一个3位数:")
try:
assert len(x) == 3, "长度必须为3" # assert exp1 exp2 断言,exp1,如果断言失败False,提示exp2
x = int(x)
break
except:
print("好像有些不对哦")
if x in lst:
print("元素{0}在列表中的索引为:{1}".format(x, lst.index(x))) # str.format() 和 占位符%s, %d,没啥区别呀
else:
print("列表中不存在该元素")
请输入一个3位数:1234
好像有些不对哦
请输入一个3位数:666
列表中不存在该元素
sort(); reserve()
Docstring: L.sort(key=None, reverse=False) -> None -- stable sort IN PLACE
x = list(range(11))
import random
random.shuffle(x) # 将列表元素随机乱序
x
[6, 4, 8, 0, 3, 1, 7, 10, 9, 5, 2]
x.sort(key=lambda s: len(str(s)), reverse=True) # 转成字符串,按字符串长度降序排列
x
[10, 6, 4, 8, 0, 3, 1, 7, 9, 5, 2]
x.sort(key=str) # 转成字符串,按大小升序排列
x
[0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]
x.sort() # 按默认规则排序(升序)
x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
x.reverse() # 元素逆序
x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
注意:列表的L.sort(key=None, reverse=False); L.reverse()是原地排序会改变元素的位置;而内置的sorte(key=None, reverse=False); reversed()则张返回新的列表对象
from operator import itemgetter
Init signature: itemgetter(self, /, *args, **kwargs)
Docstring:
itemgetter(item, ...) --> itemgetter objectReturn a callable object that fetches the given item(s) from its operand.
After f = itemgetter(2), the call f(r) returns r[2].
After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])
game_result = [['Bob', 95.0, 'A'],
['Alan', 86.0, 'C'],
['Mandy', 83.5, 'A'],
['Rob', 89.3, 'E']
]
sorted(game_result, key=itemgetter(2)) # 按子列表第三个元素"A,C,E"进行排序
[['Bob', 95.0, 'A'],
['Mandy', 83.5, 'A'],
['Alan', 86.0, 'C'],
['Rob', 89.3, 'E']]
sorted(game_result, key=itemgetter(2,0)) # 先按第3个元素,再按第一个元素排序
[['Bob', 95.0, 'A'],
['Mandy', 83.5, 'A'],
['Alan', 86.0, 'C'],
['Rob', 89.3, 'E']]
还有还多的玩法,这里就暂时不去列举了
列表对象支持运算符
x = [1,2,3]
id(x)
642845987464
x = x +[4] # + 不属于原地操作,而是返回新列表,且涉及大量元素赋值,效率非常低
id(x)
642846834248
x += [5] # += 属于原地操作,与append()方法一样高效
id(x)
642846834248
x = [1,2,3]
id(x)
642858941128
x = x*2 # 元素重复,返回新列表
print(x)
print(id(x))
[1, 2, 3, 1, 2, 3]
642847377608
x *= 2 # *= 的方式,地址不变,效率很高
3
print(x)
print(id(x))
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
642847377608
[1,2,3,3,4] * 0 # 重复0次,清空,等同于 l.clear() 或 [:] = []
[]
3 in [1,2,4] # 成员测试
False
内置函数对列表的操作
max(); min(); sum(); len();zip();map();reduce();filter();enumberate();all()....
x = list(range(11))
import random
random.shuffle(x)
x
[3, 1, 0, 9, 4, 10, 5, 8, 7, 6, 2]
all(x) # 是否所有元素都等价于True
False
any(x) # 是否存在等价于True的元素
True
max(x)
10
max(x,key=str) # 转成字符串最大
9
list(zip(x, [1] * 20)) # 多列表元素重组
[(3, 1),
(1, 1),
(0, 1),
(9, 1),
(4, 1),
(10, 1),
(5, 1),
(8, 1),
(7, 1),
(6, 1),
(2, 1)]
list(zip(['a','b','c'],[1,2]))
[('a', 1), ('b', 2)]
x
[3, 1, 0, 9, 4, 10, 5, 8, 7, 6, 2]
dict(enumerate(x)) # 组合成列表
{0: 3, 1: 1, 2: 0, 3: 9, 4: 4, 5: 10, 6: 5, 7: 8, 8: 7, 9: 6, 10: 2}
列表推导式
语法:
[ expression for i in sequence if condition1
for j in sequence if condition2
for k in sequenxe if condition3
........
for n in sequence if conditionn]
阿凡提要米问题,共64格,第一,1粒;第二,2粒;第三4粒;第四8粒....一共64格子,需要多少米
rice = sum([2 ** i for i in range(1,65)])
# 按照一斤26000粒算
total = rice / (2600 * 2 * 1000) # 用吨 来计量
print(total)
7094901566811.366
实现嵌套列表的平铺
vec = [[1,2,3], [4,5,6], [7,8,9]]
[num for elem in vec for num in elem] # 先遍历列表元素,每个元素又是个列表,再遍历每个列表,返回元素
[1, 2, 3, 4, 5, 6, 7, 8, 9]
多级嵌套还可以用递归实现
def flat_list(lst):
result = [] # 存放最终结果的列表
def nested(lst): # 函数内部嵌套函数,功能:遍历元素,直到不能够遍历为止
for i in lst:
if isinstance(i, list):
nested(i) # 递归子列表
else:
result.append(i)
nested(lst)
return result
flat_list([4,5,6,[7,8,9,[11,12,13,[13,14,15,[16,17,[18,19,[20,[21]]]]]]]])
[4, 5, 6, 7, 8, 9, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21]
过滤不符合条件元素
# 列出当前文件夹下所有Python源文件
import os
[filename for filename in os.listdir('.') if filename.endswith(('.py', '.pyw'))]
[]
a_list = [-1, -4, 6, 7.5, -2, 3, 9, -11]
[i for i in a_list if i > 0] # 所有大于0的数字 组成新列表
[6, 7.5, 3, 9]
# 给定一个成绩字典,要求计算score的最高分、最低分、平均分、最高分的同学是谁
scores = {'zs': 45,
'lisi': 78,
'wang wu': 40,
'zhao liu': 96,
'zhao qi': 65,
'sun ba': 90,
'zj': 78,
"chen jie":99
}
# 本质还是考字典操作,键、值的操作嘛,以后可能会更复杂在变量很多,嵌套很多,其实原理是一样的
high_est = max(scores.values())
low_est = min(scores.values())
average = sum(scores.values()) / len(scores)
print(high_est, low_est, average) # 同时输出最高、最低、平均分
# 寻找最高分的key 其实就是调用 ditc.items()
highest_person = [name for name, score in scores.items() if score == high_est]
print(highest_person)
99 40 73.875
['chen jie']
# 查找列表中最大元素的所有位置
import random
x = [random.randint(10, 20) for _ in range(20)] # 先写for循环(只表示循环次数,下划线,降低阅读干扰),最后再写 每次 要执行的 表达式
max_num = max(x) # 找出最大值
[index for index, value in enumerate(x) if value == max_num]
[1, 7, 15]
同时遍历多个可迭代对象
[(x,y) for x in [1,2,3] for y in [1,3,4] if x != y]
[(1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 4)]
[(x,y) for x in [1,2,3] if x == 1 for y in [3,1,4] if x != y]
[(1, 3), (1, 4)]
切片
比索引更强大的一点在于,切片不会因为下标越界而抛出异常,代码具有更强的健壮性,注意切片是生成了新的对象
a_list = [3,4,5,6,7,9,11,13,15,17]
print(id(a_list))
1043253510920
a_list[:] # 此时已经生成了新的列表
print(id(a_list))
1043253511880
a_list = a_list[::-1] # 逆序,跟l.reverse()不同在于,切片是产生新的对象,而reverse()方法是原地逆序,指针不变
print(id(a_list))
1043253511880
a_list
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
s = "张三,98"
type(s)
str
a = eval(s)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-17-e6943141c006> in <module>()
----> 1 a = eval(s)
<string> in <module>()
NameError: name '张三' is not defined
a_list[::2]
[3, 5, 7, 11, 15]
a_list[1::2]
[4, 6, 9, 13, 17]
a_list
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
a_list[3:6] # 前闭后开
[6, 7, 9]
a_list[:10000] # 自动尾部截断,不会报错
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
a_list[100:]
[]
a_list[100] # 不能越界访问
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-27-b5f68ab1fd00> in <module>()
----> 1 a_list[100] # 不能越界访问
IndexError: list index out of range
切片- 增加元素
属于原地操作,不改变列表的地址
lst = [3,5,7]
id(lst)
1043253645832
lst[len(lst):]
[]
# 在尾部增加元素, 地址不变
lst[len(lst): ] = [9]
id(lst)
1043253645832
lst[: 0] = [1,2] # 头部增加元素
print(lst)
print(id(lst))
[1, 2, 1, 2, 1, 2, 1, 2, 3, 5, 7, 9]
1043253645832
lst[1:1] = ['cj'] # 在第2个元素,前插1
lst
[1, 'cj', 'c', 'j', 'c', 'j', 2, 1, 2, 1, 2, 1, 2, 3, 5, 7, 9]
lst[3:3] = [6,6] # 在中间位置插入多个元素
lst
[1,
'cj',
'c',
6,
6,
6,
6,
6,
6,
6,
6,
6,
6,
6,
6,
'j',
'c',
'j',
2,
1,
2,
1,
2,
1,
2,
3,
5,
7,
9]
切片- 删除元素
lst = [3,5,7,9]
lst[:3] = []
lst
[9]
lst = [3,5,7,9]
del lst[:2]
lst
[7, 9]
切片- 查、改元素
lst = [1,3,5,7]
lst[:1] = [6,6]
lst
[6, 6, 6, 3, 5, 7]
lst[::2] = zip('abc', range(4))
lst
[('a', 0), 6, ('b', 1), 3, ('c', 2), 7]
元组:轻量级列表
x = (1,2,4)
type(x)
tuple
x[-1]
4
x[-1] = 666 # 支持索引查看,不能修改元素
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-58-8646078b016b> in <module>()
----> 1 x[-1] = 666 # 支持索引查看,不能修改元素
TypeError: 'tuple' object does not support item assignment
x = () # 空元组,等价于 x = tuple()
x = (3,) # 只有一个元素时,要增加一个逗号
tuple(range(5))
(0, 1, 2, 3, 4)
list(enumerate(range(5)))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
list(zip('1234', 'abcdefg'))
[('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'd')]
tuple(zip('1234', 'abcdefg'))
(('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'd'))
dict(zip('1234', 'abcdefg'))
{'1': 'a', '2': 'b', '3': 'c', '4': 'd'}
元组和列表的异同点
共同点:
- 都是有序序列,支持双向索引。都支持count();len();sum/max/min();map/fliter/reduce/zip();+ += * * = in
不同点:
- 元组属有序不可变,不同于列表可增、删、查、改,只能查,也就没有append、inset、pop、remove、可认为它是常量列表
- Python给元组进行高效优化,访问速度快于列表,如果数据只是用来遍历查看而不修改,优先考虑元组,同时元组让数据更加安全
- 元组同数字、字符串属于不可变序列,可作为字典的键,而可变的列表、集合、字典永远不能作为列表的键,可用hash()来哈希一下,对象可哈希则表示其可唯一,不可变
hash((1,)) # 测试元组对象
3430019387558
Signature: hash(obj, /)
Docstring:
Return the hash value for the given object.Two objects that compare equal must also have the same hash value, but the
reverse is not necessarily true.
hash(666) # hash 数字
666
hash("hello world") # hash 字符串
-5895774585350095353
hash([1,2,8]) # hash list
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-74-c3e4c0716b94> in <module>()
----> 1 hash([1,2,8]) # hash list
TypeError: unhashable type: 'list'
hash({'1':2, 'cj':98}) # hash dict
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-75-af1fc46d441c> in <module>()
----> 1 hash({'1':2, 'cj':98}) # hash dict
TypeError: unhashable type: 'dict'
hash({1,2,2,2,4}) # hash set
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-76-87745b5b889e> in <module>()
----> 1 hash({1,2,2,2,4}) # hash set
TypeError: unhashable type: 'set'
生成器推导式
- 写法上,就是(exp1 for-loop conditon)与列表推导式不同在于,生成器推导式的结果是一个生成器对象,而列表推导式返回列表
- 惰性求值,只在需要的时候生成新元素,空间占用非常少,尤其适合大数据处理场景
- 访问时,支持转化为列表、元组等,可用其对象的__next__()方法或内置函数next(),或用for进行遍历
- 只支持正向访问,不能再次访问已访问过的元素,也不支持使用下标访问其中的元素
- 想重新访问,只能重新创建该生成器对象。enumerate/filter/map/zip对象也是一样,还有yield
g = ((i + 2) ** 2 for i in range(10)) # 创建生成器对象
g
<generator object <genexpr> at 0x000000F2E6C3C7D8>
for i in g:
print(i, end=' ')
4 9 16 25 36 49 64 81 100 121
tuple(g) # 刚刚已经遍历了,就不能再访问了
()
g = ((i + 2) ** 2 for i in range(10)) # 重新创建生成器对象
g
<generator object <genexpr> at 0x000000F2E6C3C1A8>
g.__next__()
4
g.__next__()
9
next(g) # 使用内置函数
16
x = filter(None, range(20)) # filter 对象也有同样的特点
1 in x
True
3 in x
True
3 in x # 不能访问已经访问过的元素
False
m = map(str, range(20)) # map对象也有相同的特点
'0' in m
True
'0' in m # 不能再次访问已经访问过的元素
False
字典:对应关系映射
- 字典是一个无序可变的数据类型
- 键不允许重复,值无所谓,可作为键:数值、字符串、元组,不可作为键:列表、集合、字典等可变类型
- 字典在内部维护的哈希表使得检索操作非常快,非常高效且节约内存
字典的创建与删除
d = {'name':'cj', 'age':22, "height":173} # 直接创建
# 创建空字典
x = {}
x = dict()
key = [1,2,3,4]
value = ('a','b','c','d')
x = dict(zip(key, value))
print(x)
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
d1 = dict.fromkeys(['age', 'name', 'sex']) # 以给指定内容为 key, value 为 None
d1
{'age': None, 'name': None, 'sex': None}
Signature: dict.fromkeys(iterable, value=None, /)
Docstring: Returns a new dict with keys from iterable and values equal to value.
del d1 # 删除字典
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-100-5c2f7f3b2a7b> in <module>()
----> 1 del d1 # 删除字典
NameError: name 'd1' is not defined
字典元素访问
通过dict[key]去访问value,如不存在key则会抛出异常
d = {'name':'cj', 'age':22, "height":173}
d['name'] # 存在键,则会返回值
'cj'
d['xxx'] # 不存在键,则会抛出异常
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-104-9e01d6244f6b> in <module>()
----> 1 d['xxx'] # 不存在键,则会抛出异常
KeyError: 'xxx'
为了防止访问出错引发异常而崩溃,可以采用判断结构或异常处理来控制
d = {'name':'cj', 'age':22, "height":173}
if 'cj' in d: # 先判断 key 是否存在
print(d['cj'])
else:
print('Not exists.')
Not exists.
try:
print(d['cj'])
except:
print("Not exists.")
Not exists.
d.get('name') # 找到则返回值
'cj'
d.get('cj', "Not exists.") # 没有找到则返回第二个参数值
'Not exists.'
Docstring: D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
x = d.get('xxx') # 没有找到时,默认返回None, 应用:可以用来统计值的出现频次嘛,d.get(key, 0) + 1
print(x)
None
# 统计字符出现频次
import random
import string
x = string.ascii_letters + string.digits # 拼接24字母(大小写)和数字(0-9)
x
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
string = ''.join((random.choice(x) for i in range(1000))) # 随机生成000个字符
# string[:10]
# 统计词频
d = dict()
for s in string:
d[s] = d.get(s, 0) + 1
# 查看结果
print('词频统计结果如下:\n')
for k, v in d.items():
print(k, v)
词频统计结果如下:
P 18
V 15
2 17
d 19
g 19
e 16
R 14
y 15
x 26
D 23
N 16
0 14
B 11
I 18
Q 19
p 14
u 17
s 18
Y 23
6 21
S 15
O 15
Z 12
E 14
h 19
r 8
T 19
9 15
i 12
o 17
m 15
4 19
z 14
5 19
1 18
3 12
v 24
7 15
8 16
l 18
a 16
U 15
w 14
L 13
C 15
k 22
t 17
M 17
A 17
b 10
H 15
J 20
n 22
W 21
K 15
G 18
X 13
j 8
f 10
c 12
q 11
F 10
d = {'name':'cj', 'age':22, "height":173}
d.setdefault("sex", '男') # 新增元素,如果存在,返回值,如果不存在,则添加key-value;
d
{'name': 'cj', 'age': 22, 'height': 173, 'sex': '男'}
d.setdefault("sex", '男') # 新增元素,已经存在,不会覆盖原有数据
d
Docstring: D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
对字典对象进行迭代或者遍历时,默认是遍历字典的键
除了d.items()不算 len/ sum/ max/ min/ sorted/ enumerate /keys/ valus/ map/ filter/ in 等也遵从相同约定(key)
for k in d: # 默认是遍历字典的键
print(k, end= ' ')
name age height sex
d.keys() # key
dict_keys(['name', 'age', 'height', 'sex'])
d.values()
dict_values(['cj', 22, 173, '男'])
d.items() # 明确指定遍历字典元素 key-value
dict_items([('name', 'cj'), ('age', 22), ('height', 173), ('sex', '男')])
for k, v in d.items():
print(k, v)
name cj
age 22
height 173
sex 男
字典元素 增、改、删
d['love'] = 'reading' # 字典的增、改是一样的操作
d
{'name': 'cj', 'age': 22, 'height': 173, 'sex': '男', 'love': 'reading'}
d.update({'score':100, 'major':'marketing'}) # d.update 增加一个字典
d
{'name': 'cj',
'age': 22,
'height': 173,
'sex': '男',
'love': 'reading',
'score': 100,
'major': 'marketing'}
Docstring:
D.update([E, ]**F) -> None. Update D from dict/iterable E and F.
If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]
If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v
In either case, this is followed by: for k in F: D[k] = F[k]
del d['age'] # 删除字典元素 del d 删除全部, d.clear() 清空
d
{'name': 'cj',
'height': 173,
'sex': '男',
'love': 'reading',
'score': 100,
'major': 'marketing'}
del d['xxx'] # 删除不存在的会报异常, 可用 选择结构 或 异常处理 进行优化
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-144-379e1eeb4165> in <module>()
----> 1 del d['xxx']
KeyError: 'xxx'
d.pop('sex') # 弹出删除 指定元素 的值,对空字典会报异常哦
'男'
dict.pop(key) 指定删除;dict.popitem() 随机删除,这个有些恐怖,我觉得有很多做恐怖游戏的用武之地
d.popitem() # 弹出 随机删除 元素的key-value,对空字典会报异常哦
('major', 'marketing')
Docstring:
D.popitem() -> (k, v), remove and return some (key, value) pair as a
2-tuple; but raise KeyError if D is empty.
集合:无序可变-元素不可重复
集合同字典的键一样,数据只能包含数字、字符串、元组等不可变(可哈希)类型,不能有可变的类型如字典、列表、集合等
集合对象的创建与删除
a = {3,4,5,5,6,2,'cj', (1,3)} # 直接创建,会自动去重,且是无序的
a
{(1, 3), 2, 3, 4, 5, 6, 'cj'}
a_set = set(range(8, 14))
a_set
{8, 9, 10, 11, 12, 13}
b_set = set([1,3,2,4,9,0,4,4,3,5,2,6,6,6,6,6,]) # 转化时就自动去重了
b_set
{0, 1, 2, 3, 4, 5, 6, 9}
a = set() # 空集合
type(a)
set
集合推导式
Python具有:
- 列表推导式
- 生成器推导式(元组)
- 字典推导式
- 集合推导式
{s.strip() for s in ('she ', ',', 'i')}
{',', 'i', 'she'}
# 生成1-500间的10个随机数,并自动去重
import random
{random.randint(1, 500) for _ in range(10)}
{39, 47, 103, 136, 157, 174, 272, 346, 359, 431}
a = {1,2,4}
del a # 删除集合
a
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-161-88f0dc819981> in <module>()
----> 1 del a
2 a
NameError: name 'a' is not defined
集合操作与运算
元素的增、删
s = {1,2,3}
s.add(3) # 增加元素,重复元素则自动忽略
s.add(4)
s
{1, 2, 3, 4}
s.update({2,4,5,8}) # update 增加一个集合,同字典一样
s
{1, 2, 3, 4, 5, 8}
s.remove('x') # 删除一个元素,不存在就抛出异常,set.remove()
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-166-50960b113aed> in <module>()
----> 1 s.remove('x') # 删除一个元素,不存在就抛出异常,set.remove() 必须是数字
KeyError: 'x'
s.discard('ddd') # 元素存在则删除,不存在则忽略改操作
Docstring:
D.popitem() -> (k, v), remove and return some (key, value) pair as a
2-tuple; but raise KeyError if D is empty.
s.pop(1) # set.pop() 随机删除,并返回改元素
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-177-f06e91dfbaaa> in <module>()
----> 1 s.pop(1)
TypeError: pop() takes no arguments (1 given)
集合运算
内置函数:len/ max/ min/ sum/ sorted/ map/ filter/ enumerate/() in等也适用于集合
a = {1,2,3,4,5}
b = {4,5,6,7,8}
交集 intersection
a & b # 交集 intersection
{4, 5}
a.intersection(b)
{4, 5}
并集 union
a | b # 并集 union
{1, 2, 3, 4, 5, 6, 7, 8, 9}
a.union(b)
{1, 2, 3, 4, 5, 6, 7, 8, 9}
对称差集 symmetric_difference
a ^ b # a 与 b 不同的元素
{1, 2, 3, 6, 7, 8, 9}
a.symmetric_difference(b)
{1, 2, 3, 6, 7, 8, 9}
差集 difference
a - b # a 有而 a 没有的元素
{1, 2, 3}
a.difference(b)
{1, 2, 3}
b - a
{6, 7, 8, 9}
b.difference(a) # b 不同于 a 的元素
{6, 7, 8, 9}
子集
a = {1,2,3}
b = {1,2,3,4}
a < b # a 是b的 真子集
True
{1,2} <= {1,2} # 子集
True
a.issubset(b) # 测试是否为子集
True
Python 之禅 需要常常阅读
import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Python中, 字典、集合都使用哈希表来存储元素,其查找速度非常快,关键字 in 作用语字典和集合时,比列表要快得很多
import random
import time
x1 = list(range(10000))
x2 = tuple(range(10000))
x3 = set(range(10000))
x4 = dict(zip(range(10000), range(10000)))
r = random.randint(0, 9999)
for i in (x4, x3, x2, x1):
start = time.time()
for j in range(10000000): 执行1千万次,方便比较
pass # 执行代码而已,增加程序运行时间, 没什么实际作用
print(type(i), 'Time used:', time.time() - start )
<class 'dict'> Time used: 0.5323772430419922
<class 'set'> Time used: 0.48834705352783203
<class 'tuple'> Time used: 0.47533631324768066
<class 'list'> Time used: 0.47133350372314453
import time
time.time()
1540551645.3004868
集合应用案例-电影推荐
需求:
- 假设已经有若干用户名字及其喜欢的电影清单
- 现在用某用户,已看过,并喜欢一些电影,现想找个新电影看看,又不知道看什么好,请根据已有数据给用户做推荐
方案:
- 根据已有数据,查找与该用户最相似的用户(看过并喜欢的电影与该用户最接近的用户)
- 从他喜欢的电影中选取一个当前用户还没看过的电影,然后推荐
import random
random.randrange(1,8)
3
Signature: random.randrange(start, stop=None, step=1, _int=<class 'int'>)
Docstring:
Choose a random item from range(start, stop[, step]).
字典推导式
{'cj' + str(i): {j for j in range(5)} for i in range(5)}
{'cj0': {0, 1, 2, 3, 4},
'cj1': {0, 1, 2, 3, 4},
'cj2': {0, 1, 2, 3, 4},
'cj3': {0, 1, 2, 3, 4},
'cj4': {0, 1, 2, 3, 4}}
from random import randrange
# 其他用户喜欢看的电影清单 用户1:电影1
data = {'用户' + str(i):{"film" + str(randrange(1, 10)) for j in range(randrange(15))} for i in range(10)} # 需要好好再理解一番
# print(data)
# 需求用户 曾经看过 并感觉不错的电影
user = {'film1', 'film2', 'film3'}
# 查找与 需求用户 最为相似的 用户和他喜欢看的电影
similar_user, films = max(data.items(), key=lambda item: len(item[1] & user))
print("历史数据:")
print('** '* 27)
for k, v in data.items():
print(k, v, sep=':')
print('**'* 27)
print('和您最相似的用户是:', similar_user)
print('他最喜欢看的电影是:', similar_user)
print('他看过的电影中,您还没有看过的有:', films - user) # 两个集合的差
历史数据:
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
用户0:{'film8', 'film1', 'film9'}
用户1:{'film8', 'film4', 'film1'}
用户2:{'film4', 'film7', 'film9', 'film2', 'film1', 'film3', 'film8', 'film6'}
用户3:{'film2', 'film9'}
用户4:{'film2', 'film4'}
用户5:{'film4', 'film9', 'film1', 'film3', 'film8', 'film2'}
用户6:{'film7', 'film4', 'film1', 'film9'}
用户7:{'film5', 'film4', 'film7', 'film1', 'film3', 'film8', 'film6'}
用户8:{'film5', 'film1', 'film3', 'film8', 'film2'}
用户9:set()
******************************************************
和您最相似的用户是: 用户2
他最喜欢看的电影是: 用户2
他看过的电影中,您还没有看过的有: {'film4', 'film7', 'film9', 'film8', 'film6'}
{'cj' + str(i): {j for j in range(5)} for i in range(5)}
{'cj0': {0, 1, 2, 3, 4},
'cj1': {0, 1, 2, 3, 4},
'cj2': {0, 1, 2, 3, 4},
'cj3': {0, 1, 2, 3, 4},
'cj4': {0, 1, 2, 3, 4}}
序列解包
x, y, z = 1,2,3 # 多变量赋值
a_tuple = (False, 66.6, 'cj') # 解包元组元素
x, y, z = a_tuple
x, y, z = range(3)
x, y, z = map(str, range(9)) # 解包元素不够,就报错了,不够解呀
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-257-9e8e47dc0d96> in <module>()
----> 1 x, y, z = map(str, range(9)) # 解包元素不够,就报错了,不够解呀
ValueError: too many values to unpack (expected 3)
a, b = b, a # 直接交换两个变量的值,而无需使用第三个中介变量
d = {'a':1, 'b':2, 'c':3}
a, b, c = d.items()
print(a,b,c)
e,f,g = d.values() # d.keys() 也一样
print(e,f,g)
('a', 1) ('b', 2) ('c', 3)
1 2 3
string.format()来占位,感受一下
x = ['a', 'b', 'c']
for i, v in enumerate(x):
print("The value on the position {0} is {1}".format(i, v)) # 也没有觉得比%s,%d,%r 好用在哪里呀
The value on the position 0 is a
The value on the position 1 is b
The value on the position 2 is c
本章小结
- 列表是包含若干元素的有序连续内存空间,当对元素增删时,列表对象自动进行内存扩缩,保证相邻元素间没有缝隙
- 应尽量从列表尾部进行元素的追加和删除操作,尽量不要insert()
- 列表、元组、字符串都支持双向索引,字典支持用“键”作为下标访问元素值,集合不支持任何索引
- 切片操作作用于列表时具有最强大的功能
- 列表可变、元组不可变,这是一个非常本质的区别
- 列表推导式的结果是一个列表,元组推导式的结果是一个生成器对象
- 字典的“键”和集合的元素都不允许重复,并且必须是不可变数据类型
- 关键字 in 可作用语列表以及其他可迭代对象,包括元组、字典、列表、集合、range对象、字符串、循环结构等(常用于)
耐心和恒心, 总会获得回报的.