列表和元组基础
列表和元组都是一个可以放置任意数据类型的有序集合
# 可以包含所有的数据类型
lst = ['hello', 123, [1,2], {1:2}]
tup = ('hello', 123, [1,2], {1:2})
列表是动态的, 长度大小不固定, 可以随意的增加、删除或者该表元素(mutable)
元组是静态的, 长度大小固定, 无法增加删减或者改变(immutable)
lst = ['hello', 123, [1,2], {1:2}]
tup = ('hello', 123, [1,2], {1:2})
# 可以正常的修改数据
lst[1] = 456
print(lst)
['hello', 456, [1, 2], {1: 2}]
# 元组是不可变的, 做修改的话会报错
# 如果想对已有的元组做任何'改变', 那就只能重新开辟一块内存,创建新元组
tup[1] = 456
print(tup)
Traceback (most recent call last):
File "E:/Python/review/list_and_tuple.py", line 7, in <module>
dup[1] = 456
TypeError: 'tuple' object does not support item assignment
lst = ['hello', 123, [1,2], {1:2}]
tup = ('hello', 123, [1,2], {1:2})
# 列表只是添加到原列表末尾
print(id(lst)) # 23153240
lst.append('456')
print(id(lst)) # 23153240
# 元组做修改会重新开辟一块空间, 实际上就是创建一个新元组
print(id(tup)) # 52580096
tup = tup + ('456',)
print(id(tup)) # 52579232
元组和列表都支持索引和负索引
lst = ['hello', 123, [1,2], {1:2}]
tup = ('hello', 123, [1,2], {1:2})
print(lst[2]) # [1, 2]
print(tup[2]) # [1, 2]
print(lst[-1]) # {1: 2}
print(tup[-1]) # {1: 2}
元组和列表都支持切片操作,[开始索引, 结束索引, 步长] 步长为负反转
lst = ['hello', 123, [1,2], {1:2}]
tup = ('hello', 123, [1,2], {1:2})
print(lst[1:3]) # [123, [1, 2]]
print(tup[1:3]) # (123, [1, 2])
print(lst[::-2]) # [{1: 2}, [1, 2], 123, 'hello']
print(tup[::-1]) # ({1: 2}, 123)
列表和元组可以互相转换
lst = ['hello', 123, [1,2], {1:2}]
tup = ('hello', 123, [1,2], {1:2})
print(tuple(lst)) # ('hello', 123, [1, 2], {1: 2})
print(list(tup)) # ['hello', 123, [1, 2], {1: 2}]
列表和元组存储方式的差异
列表是动态的, 所以需要存储指针, 来指向对应的元素, 由于列表是可变的, 所以需要额外存储已经分配的长度大小, 这样才可以实时追踪列表空间的使用情况, 当空间不足时, 及时分配额外空间
lst = []
tup = ()
print(lst.__sizeof__()) # 20
print(tup.__sizeof__()) # 12
lst.append(1)
tup = tup + (1,)
print(lst.__sizeof__()) # 36 当空间不足, 列表为其分配了4个元素的空间
print(tup.__sizeof__()) # 16 每次增加4个字节
lst.append(2)
tup = tup + (2,)
print(lst.__sizeof__()) # 36 之前分配了空间, 所以列表空间不变
print(tup.__sizeof__()) # 20 同上
lst.append(3)
tup = tup + (3,)
print(lst.__sizeof__()) # 36 同上
print(tup.__sizeof__()) # 24 同上
lst.append(4)
tup = tup + (4,)
print(lst.__sizeof__()) # 36 同上
print(tup.__sizeof__()) # 28 同上
lst.append(5)
tup = tup + (5,)
print(lst.__sizeof__()) # 52 空间再次不足, 列表再次为其分配了4个元素的空间
print(tup.__sizeof__()) # 32 同上
列表: Python每次分配空间是都会额外多分配一些, 这样的机制保证了其操作的高效性: 增加/删除的时间复杂度均为O(1)
元组: 长度大小固定, 元素不可变, 所以存储空间不变
在数据较小的时候, 差异可以忽略不计, 但是如果数据是上亿以上, 那么就不能忽略了
列表和元组的性能
元组要比列表更加轻量级一些, 所以总体来说, 元组的性能速度要略优于列表
Python会在后台, 对静态数据做一些资源缓存, 通常来说因为垃圾回收机制的存在, 如果一些变量不被使用了, Python就会回收它们所占用的内存, 返还给操作系统, 以便其他变量或其他应用使用
但是对于一些静态变量, 比如元组, 如果他不被使用并且空间不大时, Python会暂时缓存这部分内存, 这样, 下次我们在创建同样大小的元组是, Python就可以不用再想操作系统发出请求, 去寻找内存, 而是可以直接分配缓存的内存空间, 这样就能大大加快程序的运行速度
python3 -m timeit (1,2,3,4,5,6)
20000000 loops, best of 5: 11.9 nsec per loop
python3 -m timeit [1,2,3,4,5,6]
5000000 loops, best of 5: 86 nsec per loop
但如果索引操作的话, 两者的速度差别非常小, 几乎可以忽略不计
如果想要增加、删减或者改变元素, 那么列表显然更优, 因为元组必须通过新建一个元组来完成
列表和元组的使用场景
如果存储的数据和数量不变, 比如你有一个函数, 需要返回的是一个地点的经纬度, 然后直接传给前端渲染, 那么肯定选用元组更合适
如果存储的数据或数量是可变的, 比如社交平台上的一个日志功能, 是统计一个用户在一周之内看了哪些用户的帖子, 那么则用列表更合适
列表内置函数
长度len
len(list) 返回列表的长度
in 与 not in
in 判断元素是否在列表中
not in 判断元素是否不在列表中
循环 for
for i in list: print(i)
追加 append
list.append(n) 在列表的最后追加n
按索引添加 insert
list.insert(n,m) 在第n个元素的位置添加m
追加一个列表 extend
list.extend([1,2,3]) 在列表的末尾一次型追加立一个序列(原组和列表)中的多个值(用新列表扩展原来的列表)
按索引删除 del
del list[n] n为列表的索引
按元素删除 remove
list.remove(n) n为列表的元素
随机移除 pop
list.pop(1) 移除列表中的某个元素,并返回该院属的值
最大值 max
max(list) 返回列表中的最大值
最小值 min
min(list) 返回列表中的最小值
统计次数 count
list.count(n) n为列表中的元素
排序 sort
list.sort() 对列表按照大小排序 reverse=True 参数 反向排序
反转 reverse
list.reverse()
元组内置函数
长度len
len(tuple) 返回元组的长度
in 与 not in
in 判断元素是否在元组中
not in 判断元素是否不在元组中
循环 for
for i in tuple: print(i)
最大值 max
max(tuple)
最小值 min
min(tuple)
总结
总的来说, 列表和元组都是有序的, 可以存储任意数据类型的集合, 区别主要在于下面的两点
1. 列表是动态的, 长度可变, 可以随意的增加、删减或改变元素, 列表的存储空间略大于元组, 性能略差与元组
2. 元组是静态的, 长度大小固定, 不可以对元素进行增加、删减或改变操作, 元组相对于列表更加轻量级, 性能稍优