列表导读

从列表开始,我们将陆续学习元组,集合,字典这4中容器类型数据。容器类型数据,只是望文生义,你大概能够猜测出这4种数据类型的作用,他们如同容器一样,可以存储int,float,bool,str。每一种容器类型数据都有各自的存储方式和要求,因此,他们适用于不同的场景。

什么是列表?

在讲解列表之前,我们先做一个简单的智力测验,我每天给你一个小球,每个小球都一模一样,且不允许你做任何标记,在第100天的时候,我要求你拿出来我第35天给你的那个小球,请你思考,你该如何存放小球,才能保证我说出天数,你拿出天数所对应的小球。

稍动一下脑筋,你就应该可以想出方法来,所有的小球都按顺序排放,第1天的小球排第1位,第2天的小球排第2位,以此类推,那么当我要求你找出第35天给你的小球时,你需要做的是从第1个小球开始数数,数到35时,这个小球就是我想要的。

列表的数据存储与访问与刚才所讲的小球摆放有着相同的道理,一切只与顺序有关,提到顺序,是不是想到了有序,是不是想到了索引?没错,列表里也有索引的概念,列表是数据的有序集合。

python基础数据类型列表(list)详解

1. python列表定义

python的列表是一种有序且可变的序列,列表使用中括号[]进行定义,各项元素之间使用逗号分隔。python的列表与其他编程语言中的数组很像,但独特之处在于python并不要求列表中的元素必须都是同一个类型,而是可以存储任意类型的数据。

列表和字符串都是序列,同样支持索引方式访问,也支持切片操作,不同于字符串的是你可以修改列表的内容。

在定义列表时,不需要指定列表的长度,也不用担心持续向列表中写入新的数据会达到存储容量限制,python列表是动态扩容的。

1. 创建列表

创建python列表有两种方式:

  1. 使用[] 创建列表
  2. 使用内置函数创建列表

使用[]创建一个空列表

empty_list = []         # 创建一个空列表

空列表的长度是0,此后你可以使用append方法向列表添加元组。

使用[]创建一个有多个元素的列表

lst = [1, '2', True, [1, 2]]

列表对存储在其中的元素类型没有要求,因此,你可以将任意类的元素存储在列表中,甚至包括列表本身,后面将要学习的元组,字典,集合,同样可以存在列表中。

使用内置函数list创建列表

lst1 = list("python")
lst2 = list([1, 2, 3])
print(lst1) # ['p', 'y', 't', 'h', 'o', 'n']
print(lst2) # [1, 2, 3]

能够作为list参数的不只是字符串和列表,任何可迭代对象都可以作为list函数的参数,list会返回一个新的列表

2. 访问列表里的元素

访问列表里的元素只能使用索引方式,它的一般代码形式如下

list[index]

在列表对象后面紧跟一对中括号[],中括号里的index是索引值,索引从0开始,正向索引逐个递增,列表的最大索引值是列表的长度减去1。python列表的索引支持反向索引,最后一个元素的索引值是-1,反向递减。以下面的列表为例

lst = [2, 3, 5, 6]

下面这张图可以很好的阐述索引的概念
python列表索引

假设你现在想要使用print语句输出列表的最后一个元素的值,你有两种方法

print(lst[3])       # 6
print(lst[-1]) # 6

一般情况下使用正向索引就足够了,但某些情况下需要操作列表倒数某个元素时,使用反向索引更容易。

3. 向列表里新增数据

向一个列表新增数据,有三个常用的方法,他们有各自的应用场景,这三个方法分别是

  1. append
  2. insert
  3. extend

append方法在列表的末尾新增数据

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

新增的数据一定会成为列表的最后一个元素,如果你想在列表中间的某个位置上插入一个新的元素,需要使用insert方法。

insert方法在指定的索引位置的前面向列表中插入一个新的元素,指定的插入索引位置是多少,新元素的索引就是多少。

lst = [1, 2, 3]
lst.insert(0, 4)
print(lst) # [4, 1, 2, 3]

在这个例子中,我使用insert方法在索引0的前面插入新元素4,插入后,4的索引就是0。由于insert只能在指定索引的前面插入,因此你无法使用insert方法在列表的末尾插入新的元素,列表的最大索引是2,如果insert指定插入索引位置为2,那么新插入元素的索引就会是2,而原本在索引2的位置上的元素将被移动到索引3的位置上。

append和inset一次只能新增一个元素,extend方法可以一次性将另一个序列里的元素追加到列表的末尾

lst1 = [1, 2, 3]
lst2 = [4, 5, 6]

lst1.extend(lst2)
print(lst1) # [1, 2, 3, 4, 5, 6]

4. 修改列表里的数据

修改列表里的某一项元素,需要通过索引方式找到元素然后重新对其赋值。

lst = [1, 2, 3]
lst[0] = 100
print(lst) # [100, 2, 3]

列表的第一个元素原本是1,现在被修改为100。

5. 删除列表中的数据

删除列表中的数据,有4种方法,分别是

  1. remove
  2. pop
  3. del
  4. clear

使用remove方法删除列表里的元素需要在方法里指明要删除的元素的值。

lst = [1, 2, 3, 2]
lst.remove(2) # 明确指明要删除2
print(lst) # [1, 3, 2]

虽然指明要删除2,但是remove方法不会将列表里所有的值为2的元素删除,它只会删除能够找到的第一个符合删除条件的值,剩余的值即便符合删除条件也不会被删除。

同时需要注意的是,如果指定要删除的元素不存在,会引发ValueError异常,因此在使用remove方法之前,务必先使用成员运算符in 或者是其他方法先确定被删除的元素是否真的在列表中。

使用pop方法删除列表里的元素时需要在方法里指明要删除的元素的索引

lst = [1, 2, 3, 2]
lst.pop(2) # 指明要删除索引为2的元素
print(lst) # [1, 2, 2]

这段代码里,pop方法明确要求删除索引为2的值,列表里,lst[2] 的值是3,因此3被删除。

使用del关键字也可以删除指定索引位置的元素

lst = [1, 2, 3, 2]
del lst[2]
print(lst) # [1, 2, 2]

clear方法清空列表,删除所有元素

lst = [1, 2, 3, 2]
lst.clear()
print(lst) # []

clear方法情况列表后,lst变为一个空列表。

6. 遍历列表

遍历列表的常用方法是使用for循环,它的模式非常固定

lst = [1, 2, 3, 2]

for item in lst:
print(item)

程序输出结果

1
2
3
2

7 列表的一些基础常规操作

使用内置函数len获取列表的长度

lst = [1, 2, 3, 2]

print(len(lst)) # 4

知晓列表的长度,就能够计算出列表的索引范围,列表的最小索引是0,最大索引是起长度值减1,这在通过索引方式遍历列表时是非常有用的

lst = [1, 2, 3, 2]

for i in range(len(lst)):
print(lst[i])

这段代码如果现在不能理解,没有关系,等学习到for循环后再回看这段代码就一目了然了。

使用算数运算符+合并两个列表

python的序列,例如字符串,列表,元组,都支持算数运算符+

lst1 = [1, 2, 3]
lst2 = [4, 5, 6]

lst3 = lst1 + lst2
print(lst3) # [1, 2, 3, 4, 5, 6]

列表lst1 与 lst2 相加得到一个新的列表lst3。

使用算数运算符*让列表里的元素个数翻倍

lst1 = [1, 2, 3]
lst2 = lst1*3
print(lst2) # [1, 2, 3, 1, 2, 3, 1, 2, 3]

lst1*3,会生成一个新的列表,新列表的长度是lst1的3倍。

使用成员运算符in判断某个元素是否在列表中

lst1 = [1, 2, 3]
print(2 in lst1) # True
print(3 not in lst1) # False

in 可用于判断一个元素是否在列表中,如果前面加一个not,就表示判断一个元素是否不在列表中。

8. 列表的常用方法

方法 功能
count() 统计某个元素在列表中出现的次数
append() 在列表末尾添加新的对象
extend 在列表末尾一次性追加另一个序列中的多个值
index 返回一个元素在列表中第一次出现的位置索引
insert() 将对象插入列表中的指定位置
pop() 删除列表中指定索引的元素,默认删除最后一个并返回该值
remove() 移除列表中某个值的第一个匹配项
reverse() 翻转列表
sort() 对列表进行排序

python嵌套列表

python嵌套列表是一个对初学者稍有困难的知识点,因此,我专门用一篇教程来对它进行讲解。所谓嵌套,是指列表里出现了其他容器类型数据,比如下面的例子

lst = [1, [1, 5], 3, [9, 8, [1, 3]], 5]
print(lst[3][2][0])
print(lst[1:4])

面对这种嵌套的列表,很多人表示很懵逼,现在,跟着我的节奏,一点点搞清楚它。

编程是一件很枯燥的事情,因为它要求你逻辑严谨,一丝不苟,这样,肯定没有天马行空的幻想来的让人舒服。

在前面讲列表的创建时,特别强调了,列表用中括号创建,列表里的数据用逗号分隔,从左往右看,第一个数据是1, 这个没有问题,关键是第二个数据,到底是[1, 5], 还是[1 ? 他们都被逗号分隔了

如果你认真思考就明白,第二个数据是[1, 5],因为[1, 5]是一个列表,是一个数据,而[1 不是一个数据,我们已经学过的数据类型里没有这种数据类型。

按照上面的思路去思考,列表里的数据如下

索引 数据
0 1
1 [1, 5]
2 3
3 [9, 8, [1, 3]]
4 5

在此基础上理解lst[3][2][0]

  1. lst[3] 的值是[9, 8, [1, 3]]
  2. [9, 8, [1, 3]] 是一个列表,列表里有3个数据,索引为2的数据是[1, 3]
  3. [1, 3]是一个列表,列表里有两个数据,索引为0的数据是1
  4. print(lst[3][2][0]) 语句输出的结果是1

现在,请不用代码,自己手写出下面语句的结果

  1. print(lst[1:4])
  2. print(lst[3][2:])
  3. print(lst[-2][1:2])

答案是

[[1, 5], 3, [9, 8, [1, 3]]]
[[1, 3]]
[8]

python列表的切片操作

python列表的切片操作是通过指定开始索引和结束索引截取原列表的一部分生成一个新的列表,它的一般形式为 [start:end),左闭右开,在实际截取时索引为end的元素不会被截取到新列表中。

1. 指定开始和结束位置

lst = [3, 4, 1, 4, 2, 5, 8]

lst1 = lst[3:6]
print(lst1)

程序输出结果为

[4, 2, 5]

切片操作的一般模式是[start:end],shart 和 end 所指的都是索引,截取时,end索引位置的元素不会被截取,这一点尤其要注意,比如上面的示例中

lst1 = lst[3:6]

索引为6的元素是8,8没有出现在结果里,截取范围是3到6,6-3=3,最终切片截取的列表长度也正好是3

在使用切片时,也可以使用倒序索引

lst = [3, 4, 1, 4, 2, 5, 8]

lst1 = lst[2:-2]
print(lst1)

程序输出结果

[1, 4, 2]

2. 指定开始位置,不指定结束位置

lst = [3, 4, 1, 4, 2, 5, 8]

lst1 = lst[2:]
print(lst1)

如果不指定结束位置,那么切片操作会从开始位置截取到列表末尾,程序输出结果为

[1, 4, 2, 5, 8]

3. 指定结束位置,不指定开始位置

lst = [3, 4, 1, 4, 2, 5, 8]

lst1 = lst[:5]
print(lst1)

如果不指定开始位置,那么默认开始位置为0,程序输出结果为

[3, 4, 1, 4, 2]

4. 切片操作允许索引超出范围

lst = [3, 4, 1, 4, 2, 5, 8]

lst1 = lst[:11]
print(lst1)

上面的代码中,结束位置的索引设置为11,显然已经超出了列表索引的范围,但是却没有引发错误,对于这种情况,切片操作自身做了处理,如果结束位置的索引超出索引范围,那么就以列表长度作为结束位置

5. 为什么切片操作要求左闭右开

不论是字符串的切片操作还是列表的切片操作,即使指定了切片范围的结束索引,切片操作生成的新对象也不会包括结束索引位置的元素,切片的索引范围是左闭右开的,这在第一小节里做了介绍。本节要讨论的是,为什么有这样的设定和要求,包含结束索引位置的元素就不行么?

之所以要求切片索引范围做到左闭右开,根本原因在于索引是从0开始的,左闭右开将有如下好处:

  1. 如果只指定结束索引,那么很容易就看出切片的长度,比如lst[:3],切片后生成的新列表长度就是3
  2. 如果指定了开始索引和结束索引,那么很容易就能够计算出切片的长度,比如lst[2:7], 切片的长度是7-2 = 5
  3. 左闭右开很容易通过一个索引将列表切分成两份,比如lst[:5] 和 lst[5:]

6. 指定切片间隔

关于切片间隔,已经在字符串切片操作做过讲解,本文不做赘述,只给出示例代码,想要了解切片间隔,可以去看这篇文章。

lst = [1, 2, 3, 4, 5]

print(lst[::-2]) # [5, 3, 1]
print(lst[::-1]) # [5, 4, 3, 2, 1]

7. 切片操作应用示例—分组

lst = [2, 3, 4, 1, 5, 2, 7, 1, 8, 9, 10, 31, 22, 34]

上面定义了一个列表,现在要求你从第一个元素开始,每三个一组求和,将所求得的和放入新列表sum_lst

示例代码

lst = [2, 3, 4, 1, 5, 2, 7, 1, 8, 9, 10, 31, 22, 34]

step = 3
sum_lst = []
for i in range(0, len(lst), step):
tmp = lst[i: i+step]
sum_lst.append(sum(tmp))

print(sum_lst)

python列表方法详解

下表是列表方法及功能说明

方法 功能
count() 统计某个元素在列表中出现的次数
append() 在列表末尾添加新的对象
extend 在列表末尾一次性追加另一个序列中的多个值
index 返回一个元素在列表中第一次出现的位置索引
insert() 将对象插入列表中的指定位置
pop() 删除列表中指定索引的元素,默认删除最后一个并返回该值
remove() 移除列表中某个值的第一个匹配项
reverse() 翻转列表
sort() 对列表进行排序

python列表练习题

列表的练习题非常多,多到我相信会有很大一部分人会跳过这篇教程,不过请放心,不论你是因为图省事还是因为太懒了而跳过本篇教程,将来你都会再回到这里,乖乖的做这些练习题。

编程,既是一门知识,也是一项技能,仅从学习知识的角度看,许多知识都是一看就懂的,但作为一项技能,它需要你反复练习以达到熟练的程度。

就好比骑自行车,坐上去,两脚蹬脚踏板,自行车就可以移动了,这是知识,别人一说你就懂。但是,骑上去就发现,你无法掌握平衡,只有多加练习,才能真正的掌握骑自行车的技术。

1. 列表基础考察

已知一个列表
lst = [1,2,3,4,5]

  1. 求列表的长度
  2. 判断6 是否在列表中
  3. lst + [6, 7, 8] 的结果是什么?
  4. lst*2 的结果是什么
  5. 列表里元素的最大值是多少
  6. 列表里元素的最小值是多少
  7. 列表里所有元素的和是多少
  8. 在索引1的位置新增一个的元素10
  9. 在列表的末尾新增一个元素20

答案如下

1. len(lst)
2. 6 in lst
3. [1,2,3,4,5,6,7,8]
4. [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
5. max(lst)
6. min(lst)
7. sum(lst)
8. lst.insert(1, 10)
9. lst.append(20)

以上都是对列表基础操作,所用到的每一个函数,列表的每一个方法,都是需要你熟记于心的

2. 修改列表

lst = [1, [4, 6], True]
请将列表里所有数字修改成原来的两倍

答案如下

lst[0] = 2
lst[1][0] = 8
lst[1][1] = 12

你以为存在一个函数,其功能便是将列表里所有的数据都变成原来的两倍,这样才显得变成语言是一个非常神奇的东西,但是很遗憾的告诉你,那些神奇的东西都是程序员自己实现的。

想要修改列表里的数据,必须通过索引对其重新赋值,上面的方法很low,你也可以写一个函数来实现这个功能,我们假设要处理的列表里只int,float,bool,和list数据,不管嵌套几层list,这个函数都应该能正确处理,下面是一段示例代码

def double_list(lst):
for index, item in enumerate(lst):
if isinstance(item, bool):
continue
if isinstance(item, (int, float)):
lst[index] *= 2
if isinstance(item, list):
double_list(item)


if __name__ == '__main__':
lst = [1, [4, 6], True]
double_list(lst)
print(lst)

现在,我们还没有学习到函数,更没有学习到递归函数,这个练习题,你只掌握直接通过索引修改列表即可,等到学习函数后,可以再回到这里做这个练习题。

3. 合并列表

lst = [1,2,3]
lst2 = [4,5,6]
不使用 + 号运算符,将lst2合并到lst的末尾,并思考,这个过程中,是否产生了新的列表

答案

lst.extend(lst2)

这个过程中不会产生新的列表,最直观的检验方式就是print(id(lst)),合并前后,lst的内存地址都没有发生变化,只是列表里的内容发生了变化

4. 统计练习

列表lst 内容如下

lst = [2, 5, 6, 7, 8, 9, 2, 9, 9]

请写程序完成下列题目

  1. 找出列表里的最大值
  2. 找出列表里的最小值
  3. 找出列表里最大值的个数
  4. 计算列表里所有元素的和
  5. 计算列表里元素的平均值
  6. 计算列表的长度
  7. 找出元素6在列表中的索引

答案

1. max(lst)
2. min(lst)
3. lst.count(max(lst))
4. sum(lst)
5. sum(lst)/float(len(lst))
6. len(lst)
7. lst.index(6)

这道题考察的是你对内置函数的理解和运用

下面的题目不允许写代码,仅凭思考来回答

  1. lst[2:4] 的值是什么
  2. lst[1: -3]的值是什么
  3. lst[-5]的值是什么
  4. lst[:-4] 的值是什么
  5. lst[-4:] 的值是什么

这个题目主要考察你对列表切片操作的理解

1. [6, 7]
2. [5, 6, 7, 8, 9]
3. 8
4. [2, 5, 6, 7, 8]
5. [9, 2, 9, 9]

列表的切片操作,最关键的一点在于左闭右开,结束位置的数据不会列入结果中

5. 列表操作练习

列表lst 内容如下

lst = [2, 5, 6, 7, 8, 9, 2, 9, 9]

请写程序完成下列操作

  1. 在列表的末尾增加元素15
  2. 在列表的中间位置插入元素20
  3. 将列表[2, 5, 6]合并到lst中
  4. 移除列表中索引为3的元素
  5. 翻转列表里的所有元素
  6. 对列表里的元素进行排序,从小到大一次,从大到小一次

答案

1. lst.append(15)
2. lst.insert(len(lst)//2, 20)
3. lst.extend([2, 5, 6])
4. lst.remove(lst[3])
5. lst = lst[::-1]
6. lst.sort() lst.sort(reverse=True)

6. 复杂列表练习

列表lst 内容如下

lst = [1, 4, 5, [1, 3, 5, 6, [8, 9, 10, 12]]]

不写任何代码,仅凭思考推理来回答下列问题

  1. 列表lst的长度是多少
  2. 列表lst中有几个元素
  3. lst[1] 的数据类型是什么
  4. lst[3]的数据类型是什么
  5. lst[3][4] 的值是什么
  6. 如果才能访问到 9 这个值
  7. 执行lst[3][4].append([5, 6])后,列表lst的内容是什么,手写出来
  8. lst[-1][-1][-2]的值是什么
  9. lst[-2]的值是什么
  10. len(lst[-1]) 的值是什么
  11. len(lst[-1][-1])的值是什么
  12. lst[-1][1:3] 的值是什么
  13. lst[-1][-1][1:-2]的值是什么

第1题和第2题其实是一个意思,原本统计列表里数据个数不是什么难事,可一旦出现了嵌套列表的情况,有人就分不清了,列表里的数据是以逗号分隔的,lst[3] 是一个列表,其余都是int类型数据,因此lst的长度是4

第3题,lst[1] = 4,是int类型数据
第4题,lst[3] 的数据类型是列表
第5题,lst[3]的值是[1, 3, 5, 6, [8, 9, 10, 12]],仍然是一个列表,其索引为4的数据是[8, 9, 10, 12],是列表
第6题,lst[3][4][1]
第7题,[1, 4, 5, [1, 3, 5, 6, [8, 9, 10, 12, [5, 6]]]],参考5,6两个题目的解答
第8题,lst[-1]的值是[1, 3, 5, 6, [8, 9, 10, 12]], 再次取索引为-1的数据为[8, 9, 10, 12],取索引为-2的数据为10
第9题,5
第10题,5
第11题,4
第12题, [3, 5], lst[-1]的值是[1, 3, 5, 6, [8, 9, 10, 12]]
第13题,[9], lst[-1][-1]的值是[8, 9, 10, 12],切片起始位置索引是1,值为9,结束位置是-2,值为10,由于左闭右开,最终结果是[9]