Python列表和元组

以下内容是整理极客时间Python核心技术与实战课程的笔记。

列表(list)和元组(tuple)是Python最常用两种基本结构

列表和元组的基本概念

1、那么列表和元组是什么呢
列表和元素都是一个可以放置任意数据类型的有序集合
2、那么他们的异同呢
举个例子,Python中的列表和元组同时可以存着int或者string类型的元素,其他语言则必须类型一致。例子如下。

list = [1, 2, 'hello', 'world'] # 列表中同时含有 int 和 string 类型的元素
tup = ('jason', 22) # 元组中同时含有 int 和 string 类型的元素
print(list)
print(tup)
# [1, 2, 'hello', 'world']
# ('jason', 22)

这个是Python中的共性,当然,他们也有不同点
具体的区别如下:

  • 列表是动态的,长度大小不固定,可以随意地增加、删减或者改变元素(mutable)。
  • 而元组是静态的,长度大小固定,无法增加删减或者改变(immutable)。

通过一个例子来说明。
对于列表,可以随意的将最后一个值重新赋值,但是对于元组来说,这样的操作,Python就报错,原因是tuple不可变。

list = [2, 3, 6, 8]
list[3] = 40 # 和很多语言类似,python 中索引同样从 0 开始,l[3] 表示访问列表的第四个元素
print(list)
[2, 3, 6, 40]
 
tup = (1, 2, 3, 4)
tup[3] = 40
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

那么如何改变已有元组的值呢
若相对已有的元组改变值,那么就需要重新申请内存,此时,就只能创建一个新的元组,也就是说,如果要给原来元组新加一个值,那么其实是重新创建了一个元组,然后在原来的元组的基础上增加了一个值,具体操作如下。

tup = (1, 2, 3, 4)
new_tup = tup + (5, ) # 创建新的元组 new_tup,将原来的值补充上
print(new_tup)
# (1, 2, 3, 4, 5)

对于列表,直接追加即可

list_demo = [1, 2, 3, 4]
list_demo.append(5) 
print(list_demo)
# [1, 2, 3, 4, 5]

元组和列表使用的基本操作

1、负数索引
Python是支持负数索引,-1表示最后一个元素,-4表示倒数第四个元素。举个例子。

list_demo = [1, 2, 3, 4]
print(list_demo[-1])
# 4
 
tup_demo = (1, 2, 3, 4)
print(tup_demo[-1])
# 4

2、切片操作
列表和元素都支持切片操作

list_demo = [1, 2, 3, 4]
print(list_demo[1:3]) 
# [2, 3]
 
tup_demo = (1, 2, 3, 4)
print(tup_demo[1:3]) 
# (2, 3) 

3、随意嵌套
具体请看例子

# 列表里面的每一个元素也是一个列表
list_demo = [[1, 2, 3], [4, 5]] 
# 元组的每一个元素也是一元组
tup_demo = ((1, 2, 3), (4, 5, 6)) 

4、相互转换
两者也可以通过 list() 和 tuple() 函数相互转换

# 用list将一个元组转成列表
list((1, 2, 3))
# [1, 2, 3]
 # 用一个tuple元素将一个列表转成元组
tuple([1, 2, 3])
# (1, 2, 3)

5、常用内置函数

  • count(item) 表示统计列表 / 元组中 item 出现的次数。
  • index(item) 表示返回列表 / 元组中 item 第一次出现的索引。
  • list.reverse() 和 list.sort() 分别表示原地倒转列表和排序(元组没有内置的这两个函数)。
  • reversed() 和 sorted()同样表示对列表 / 元组进行倒转和排序,但是会返回一个倒转后或者排好序的新的列表 / 元组。
    举个例子
list_demo = [3, 2, 3, 7, 8, 1]
list_demo.count(3) # 统计value=3的元素个数
# 2
list_demo.index(7) # 元素中7第一次出现的下标
# 3
list_demo.reverse() # 列表转置
# [1, 8, 7, 3, 2, 3]
list_demo.sort()  # 列表排序,从小到大
print(list_demo)
# [1, 2, 3, 3, 7, 8]
 
tup = (3, 2, 3, 7, 8, 1)
tup.count(3)
# 2
tup.index(7)
# 3
list(reversed(tup)) # 元组的转置
# [1, 8, 7, 3, 2, 3]
sorted(tup) # 元组的排序
# [1, 2, 3, 3, 7, 8]

列表和元组的存储方式的区别

列表和元组的最大区别就是一个是可变的,一个是静态的,那么他们之间的存储方式的区别是什么?
对于下面这个例子来说,对于元组和列表,放置相同的元素,但是元组的存储空间比列表占用的小

list_demo = [1, 2, 3]
list_demo.__sizeof__()
# 64
tup_demo = (1, 2, 3)
tup_demo.__sizeof__()
# 48

那为什么相同元素列表的存储空间占用比元组的大呢?
由于列表是动态的,那么它就需要需要存储指针来指向对应的元素,对于int类型的数据,占用8个字节,同时,需要额外存储已经分配的长度大小,也是8个字节,如上面这个例子,这样子做的目的就是,能检测当列表空间不够的时候,重新及时的分配额外的空间大小。

list_demo = []
list_demo.__sizeof__() #  空列表的存储空间为 40 字节
# 40
list_demo.append(1)
list_demo.__sizeof__() 
# 72  加入了元素 1 之后,列表为其分配了可以存储 4 个元素的空间 (72 - 40)/8 = 4
list_demo.append(2) 
list_demo.__sizeof__()
# 72  由于之前分配了空间还用,不会去重新分配内存,所以加入元素 2,列表空间不变
list_demo.append(3)
list_demo.__sizeof__() 
# 72 
list_demo.append(4)
list_demo.__sizeof__() 
# 72 
list_demo.append(5)
list_demo.__sizeof__() 
# 104  加入元素 5 之后,列表的空间不足,默认分配的4个空间用完了,所以又额外分配了可以存储 4 个元素的空间

在上面例子,发现一个问题。
为什么Python 每次分配空间时都会额外多分配一些
这样是为了列表动态添加元素的时候,为了减小每次增加 / 删减操作时空间分配的开销。保证了其操作的高效性:增加 / 删除的时间复杂度均为 O(1)。这样的机制称为over-allocating
对于元组元组长度大小固定,元素不可变,所以存储空间固定。

列表和元组的性能

通过上面的例子我们可以知道,元组要比列表更加轻量级一些,所以总体上来说,元组的性能速度要略优于列表。
Python 会在后台对静态数据做一些资源缓存,通常来说,因为垃圾回收机制的存在,如果一些变量不被使用了,Python 就会回收它们所占用的内存,返还给操作系统,以便其他变量或其他应用使用。

但是对于一些静态变量,比如元组,如果它不被使用并且占用空间不大时,Python 会暂时缓存这部分内存。这样,下次我们再创建同样大小的元组时,Python 就可以不用再向操作系统发出请求,去寻找内存,而是可以直接分配之前缓存的内存空间,这样就能大大加快程序的运行速度。
第一个例子,计算初始化一个相同元素的列表和元组分别所需的时间。我们可以看到,元组的初始化速度,要比列表快 5 倍。

python3 -m timeit 'x=(1,2,3,4,5,6)'
20000000 loops, best of 5: 9.97 nsec per loop
python3 -m timeit 'x=[1,2,3,4,5,6]'
5000000 loops, best of 5: 50.1 nsec per loop

第二个例子,对于索引操作的话,两者的速度差别非常小,几乎可以忽略不计。

python3 -m timeit -s 'x=[1,2,3,4,5,6]' 'y=x[3]'
10000000 loops, best of 5: 22.2 nsec per loop
python3 -m timeit -s 'x=(1,2,3,4,5,6)' 'y=x[3]'
10000000 loops, best of 5: 21.9 nsec per loop

如果你想要增加、删减或者改变元素,那么列表显然更优。因为对于元组,你必须得通过新建一个元组来完成。

列表和元组的使用场景

  1. 如果存储的数据和数量不变,比如你有一个函数,需要返回的是一个地点的经纬度,然后直接传给前端渲染,那么肯定选用元组更合适。
  2. 如果存储的数据或数量是可变的,比如社交平台上的一个日志功能,是统计一个用户在一周之内看了哪些用户的帖子,那么则用列表更合适。

一些有关list和tuple的问题

1、下面两种方式,那种创建一个空列表的效率更好?

empty_list = list()
empty_list = []

[] 的创建方法是直接调用内置的c函数, 可以直接调用,效率高,而list()的创建方式,需要Python做出来,效率较低。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值