3. 列表

在Python中,我们经常需要处理和组织多个数据的,而不是仅对少量数据进行操作。内置容器就是为我们提供了方便的方式,来取存储和管理数据的集合。
之前学习过的数字 布尔 字符串 复数 空值 都是Python的内置基本数据
Python中内置容器:
列表 元组 集合 字典
序列,是一种特殊的内置容器,主要强调的是元素的有序性和可迭代性
有序性:不是指排序问题,而是指元素的出入顺序是可以确定的。
可迭代性:按照一定的顺序进行访问,序列其实就是一个线性表

列表 list
列表是一种有序的集合,可以用它来保存多个数据,可以随时添加和删除其中的元素。
使用 [] 来定义列表,列表中的多个元素用逗号进行分隔

python
list1 = [35, 12, 99, 68, 55, 35, 87]
list2 = ['Python', 'Java', 'Go', 'Kotlin']
list3 = [100, 12.3, 'Python', True]
print(list1)  # [35, 12, 99, 68, 55, 35, 87]
print(list2)  # ['Python', 'Java', 'Go', 'Kotlin']
print(list3)  # [100, 12.3, 'Python', True]

▶ 运行结果:

输出
[35, 12, 99, 68, 55, 35, 87]
['Python', 'Java', 'Go', 'Kotlin']
[100, 12.3, 'Python', True]

除此以外,还可以通过 Python 内置的list函数将其他序列变成列表。准确的说,list并不是一个普通的函数,它是创建列表对象的构造器,后面的课程会为大家介绍对象和构造器这些概念。

python
list4 = list(range(1, 10))
list5 = list('hello')
print(list4)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(list5)  # ['h', 'e', 'l', 'l', 'o']

▶ 运行结果:

输出
[1, 2, 3, 4, 5, 6, 7, 8, 9]
['h', 'e', 'l', 'l', 'o']

序列的通用操作
(1)索引

也叫做角标、下标,表示的是元素在序列中的位置。对于一个长度为n的序列而言,索引范围[0, n-1]。其次,序列也只是负数索引,表示倒数第几个的元素,索引范围[-1,-n]

python
arr = [1, 2, 3, 4, 5]
print(arr[0])
print(arr[4])
# print(arr[6]) # IndexError: list index out of range
print(arr[-1])
print(arr[-5])
# print(arr[-6]) # IndexError: list index out of range

▶ 运行结果:

输出
1
5
5
1

(2)切片
就是一种快速获取序列中连续的子区间使用的
sequence[start:stop:step]:这个和range(a,b,c)很像,[start, stop)
start:开始索引,默认为 0
stop:最后索引,默认为 n
step:步长,默认为1
正步长 > 0,start在前,stop在后,start -> stop 从左向右
负步长 < 0,start在后,stop在前,stop -> start 从右向左

python
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(arr[:])  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(arr[::2])  # [1, 3, 5, 7, 9]
print(arr[::-1])  # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
print(arr[3:])  # [4, 5, 6, 7, 8, 9, 10]
print(arr[3:8])  # [4, 5, 6, 7, 8]
print(arr[2:8:2])  # [3, 5, 7]
print(arr[-6:-2:2])  # [5, 7]
print(arr[-2:-6:2])  # []
print(arr[-2:-6:-2])  # [9, 7]
print(arr[:8:2])  # [1, 3, 5, 7]
print(arr[-7:8:2])  # [4, 6, 8]

▶ 运行结果:

输出
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 3, 5, 7, 9]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[4, 5, 6, 7, 8, 9, 10]
[4, 5, 6, 7, 8]
[3, 5, 7]
[5, 7]
[]
[9, 7]
[1, 3, 5, 7]
[4, 6, 8]

(3)连接与重复
+ 拼接
* 重复

4)长度与最值
主要用的是内置函数 len()、min()、max()

python
arr = [1, 3, 2, 4, 6, 8, 9, 4, 2]
print(len(arr))
print(min(arr))
print(max(arr))

▶ 运行结果:

输出
9
1
9

(5)成员存在性
in和not in,用于判断元素是否存在于序列当中

列表对象函数
内置函数:不需要导入任何东西,直接使用即可
自定义函数:用户自定义的内容,先定义再调用
对象函数:必须通过某一个对象来去调用的函数,而且这些函数已经被创建好了。

对象.函数名称()
(1)append(object):默认在表尾添加元素object

(2)insert(index, object):在指定角标index处,插入元素object,如果索引右边越界加表尾,左边越界加表头。

python
arr = []
arr.append(1)
arr.append(2)
arr.append(3)
print(arr)
arr.insert(1, 4)
print(arr)
arr.insert(666, 5)
print(arr)
arr.insert(-666, 6)
print(arr)

▶ 运行结果:

输出
[1, 2, 3]
[1, 4, 2, 3]
[1, 4, 2, 3, 5]
[6, 1, 4, 2, 3, 5]

(3)extend(sequence):将其他序列中的元素依次添加在表尾,相当于把其他序列中的元素依次append()

python
arr1 = [1, 2, 3]
arr2 = [4, 5, 6]
arr3 = [7, 8, 9]
arr2.append(arr1)
print(arr2)
arr3.extend(arr1)
print(arr3)

▶ 运行结果:

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

(4)remove(value):从左到右删除列表中第一次出现的元素value,没有返回值,找不到会报错

(5)pop(index):删除指定角标index处的元素,并将其返回,如果角标不在合法范围内,则报错,如果不写index则默认删除表尾。

(6)del 关键字:不是列表对象函数,删除指定元素但不返回其指

python
arr4 = [1, 2, 3, 1, 2, 3, 1, 2, 3]
arr4.remove(1)
print(arr4)
# arr4.remove(6) # ValueError: list.remove(x): x not in list
print(arr4.pop(1))
print(arr4)
print(arr4.pop())
print(arr4)
del arr4[3]
print(arr4)
del arr4[::2]
print(arr4)

▶ 运行结果:

输出
[2, 3, 1, 2, 3, 1, 2, 3]
3
[2, 1, 2, 3, 1, 2, 3]
3
[2, 1, 2, 3, 1, 2]
[2, 1, 2, 1, 2]
[1, 1]

(7)sort():排序

(8)reverse():反转列表

(9)count(value):统计元素value出现的次数

(10)index(value):从左到右查找value第一次出现的角标

(11)clear():清空列表

(12)copy():浅层拷贝

python
arr5 = [5, 4, 9, 1, 8, 2, 3, 7, 6]
arr5.sort()  # 默认按升序排列
print(arr5)

arr5 = [5, 4, 9, 1, 8, 2, 3, 7, 6]
arr5.sort(reverse=True)  # 降序排列
print(arr5)

arr5.reverse()
print(arr5)

arr6 = [1, 2, 3, 1, 2, 3, 1, 1, 1, 2, 3, 1, 2, 3]
print(arr6.count(1))

print(arr6.index(3))
arr6.clear()
print(arr6)

arr1 = [1, 2, 3, 4, 5]
arr2 = arr1.copy()
arr1[0] = 666
print(arr1)
print(arr2)

arr1 = [1, 2, [3, 4, 5]]
arr2 = arr1.copy()
arr1[2][1] = 666
print(arr1)
print(arr2)

arr1[2] = [9, 8, 7]
print(arr1)
print(arr2)

# 列表的运算

▶ 运行结果:

输出
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
6
2
[]
[666, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, [3, 666, 5]]
[1, 2, [3, 666, 5]]
[1, 2, [9, 8, 7]]
[1, 2, [3, 666, 5]]

使用+运算符实现两个列表的拼接,拼接运算会将两个列表中的元素连接起来放到一个列表中
使用*运算符实现列表的重复运算,*运算符会将列表元素重复指定的次数
使用in或not in运算符判断一个元素在不在列表中

python
list5 = [35, 12, 99, 45, 66]
list6 = [45, 58, 29]
list7 = ['Python', 'Java', 'JavaScript']
print(list5 + list6)  # [35, 12, 99, 45, 66, 45, 58, 29]
print(list6 + list7)  # [45, 58, 29, 'Python', 'Java', 'JavaScript']
list5 += list6
print(list5)  # [35, 12, 99, 45, 66, 45, 58, 29]

▶ 运行结果:

输出
[35, 12, 99, 45, 66, 45, 58, 29]
[45, 58, 29, 'Python', 'Java', 'JavaScript']
[35, 12, 99, 45, 66, 45, 58, 29]

由于列表中有多个元素,而且元素是按照特定顺序放在列表中的,所以当我们想操作列表中的某个元素时,可以使用[]运算符,通过在[]中指定元素的位置来访问该元素,这种运算称为索引运算。
需要说明的是,[]的元素位置可以是0到N - 1的整数,也可以是-1到-N的整数,分别称为正向索引和反向索引,其中N代表列表元素的个数。对于正向索引,[0]可以访问列表中的第一个元素,[N - 1]可以访问最后一个元素;对于反向索引,[-1]可以访问列表中的最后一个元素,[-N]可以访问第一个元素
在使用索引运算的时候要避免出现索引越界的情况,导致程序崩溃,对应的错误信息是:list index out of range,翻译成中文就是“数组索引超出范围”。

python
list1 = ['苹果', '香蕉', '西瓜', '梨子', '葡萄']
print(list1[0])  # 苹果
print(list1[2])  # 西瓜
print(list1[4])  # 葡萄
list1[2] = '哈密瓜'
print(list1)  # ['苹果', '香蕉', '哈密瓜', '梨子', '葡萄']
print(list1[-5])  # 苹果
print(list1[-4])  # 香蕉
print(list1[-1])  # 葡萄
list1[-4] = '桔子'
print(list1)  # ['苹果', '桔子', '哈密瓜', '梨子', '葡萄']

# 切片

▶ 运行结果:

输出
苹果
西瓜
葡萄
['苹果', '香蕉', '哈密瓜', '梨子', '葡萄']
苹果
香蕉
葡萄
['苹果', '桔子', '哈密瓜', '梨子', '葡萄']

如果希望一次性访问列表中的多个元素,我们可以使用切片运算。切片运算是形如[start:end:stride]的运算符,其中start代表访问列表元素的起始位置,end代表访问列表元素的终止位置(终止位置的元素无法访问),而stride则代表了跨度,简单的说就是位置的增量,比如我们访问的第一个元素在start位置,那么第二个元素就在start + stride位置,当然start + stride要小于end。

python
print(list1[1:3:1])  # ['桔子', '哈密瓜']
print(list1[0:3:1])  # ['苹果', '桔子', '哈密瓜']
print(list1[0:5:2])  # ['苹果', '哈密瓜', '葡萄']
print(list1[-4:-2:1])  # ['桔子', '哈密瓜']
print(list1[-2:-6:-1])  # ['梨子', '哈密瓜', '桔子', '苹果']

print(list1[1:3])  # ['桔子', '哈密瓜']
print(list1[:3:1])  # ['苹果', '桔子', '哈密瓜']
print(list1[::2])  # ['苹果', '哈密瓜', '葡萄']
print(list1[-4:-2])  # ['桔子', '哈密瓜']
print(list1[-2::-1])  # ['梨子', '哈密瓜', '桔子', '苹果']

▶ 运行结果:

输出
['桔子', '哈密瓜']
['苹果', '桔子', '哈密瓜']
['苹果', '哈密瓜', '葡萄']
['桔子', '哈密瓜']
['梨子', '哈密瓜', '桔子', '苹果']
['桔子', '哈密瓜']
['苹果', '桔子', '哈密瓜']
['苹果', '哈密瓜', '葡萄']
['桔子', '哈密瓜']
['梨子', '哈密瓜', '桔子', '苹果']

我们还可以通过切片操作修改列表中的元素

python
list1[1:3] = ['白菜', '萝卜']
print(list1)  # ['苹果', '白菜', '萝卜', '梨子', '葡萄']

▶ 运行结果:

输出
['苹果', '白菜', '萝卜', '梨子', '葡萄']

两个列表还可以做关系运算,我们可以比较两个列表是否相等,也可以给两个列表比大小

python
nums1 = [1, 2, 3, 4]
nums2 = list(range(1, 5))
nums3 = [3, 2, 1]
print(nums1 == nums2)  # True
print(nums1 != nums2)  # False
print(nums1 <= nums3)  # True
print(nums2 >= nums3)  # False

▶ 运行结果:

输出
True
False
True
False

元素的遍历
如果想逐个取出列表中的元素,可以使用for-in循环的,有以下两种做法。

python
# 方法一:在循环结构中通过索引运算,遍历列表元素。
languages = ['Python', 'Java', 'C++', 'Fortran']
for index in range(len(languages)):
    print(languages[index])

# 方法二:直接对列表做循环,循环变量就是列表元素的代表。
languages = ['Python', 'Java', 'C++', 'Fortran']
for language in languages:
    print(language)

▶ 运行结果:

输出
Python
Java
C++
Fortran
Python
Java
C++
Fortran

列表的方法
添加和删除元素
我们可以使用列表的append方法向列表中追加元素,使用insert方法向列表中插入元素。追加指的是将元素添加到列表的末尾,而插入则是在指定的位置添加新元素

python
languages = ['Python', 'Java', 'C++']
languages.append('JavaScript')
print(languages)  # ['Python', 'Java', 'C++', 'JavaScript']
languages.insert(1, 'SQL')
print(languages)  # ['Python', 'SQL', 'Java', 'C++', 'JavaScript']

▶ 运行结果:

输出
['Python', 'Java', 'C++', 'JavaScript']
['Python', 'SQL', 'Java', 'C++', 'JavaScript']

我们可以用列表的remove方法从列表中删除指定元素,需要注意的是,如果要删除的元素并不在列表中,会引发ValueError错误导致程序崩溃,所以建议大家在删除元素时,先用之前讲过的成员运算做一个判断。我们还可以使用pop方法从列表中删除元素,pop方法默认删除列表中的最后一个元素,当然也可以给一个位置,删除指定位置的元素。在使用pop方法删除元素时,如果索引的值超出了范围,会引发IndexError异常,导致程序崩溃。除此之外,列表还有一个clear方法,可以清空列表中的元素,

python
languages = ['Python', 'SQL', 'Java', 'C++', 'JavaScript']
if 'Java' in languages:
    languages.remove('Java')
if 'Swift' in languages:
    languages.remove('Swift')
print(languages)  # ['Python', 'SQL', C++', 'JavaScript']
languages.pop()
temp = languages.pop(1)
print(temp)  # SQL
languages.append(temp)
print(languages)  # ['Python', C++', 'SQL']
languages.clear()
print(languages)  # []

▶ 运行结果:

输出
['Python', 'SQL', 'C++', 'JavaScript']
SQL
['Python', 'C++', 'SQL']
[]

从列表中删除元素其实还有一种方式,就是使用 Python 中的del关键字后面跟要删除的元素

python
items = ['Python', 'Java', 'C++']
del items[1]
print(items)  # ['Python', 'C++']

▶ 运行结果:

输出
['Python', 'C++']

元素位置和频次
列表的index方法可以查找某个元素在列表中的索引位置,如果找不到指定的元素,index方法会引发ValueError错误;列表的count方法可以统计一个元素在列表中出现的次数,

python
items = ['Python', 'Java', 'Java', 'C++', 'Kotlin', 'Python']
print(items.index('Python'))  # 0
# 从索引位置1开始查找'Python'
print(items.index('Python', 1))  # 5
print(items.count('Python'))  # 2
print(items.count('Kotlin'))  # 1
print(items.count('Swift'))  # 0
# 从索引位置3开始查找'Java'
print(items.index('Java', 3))  # ValueError: 'Java' is not in list

▶ 运行结果:

输出
0
5
2
1
0
<运行时错误: ValueError: 'Java' is not in list>

元素排序和反转
列表的sort操作可以实现列表元素的排序,而reverse操作可以实现元素的反转

python
items = ['Python', 'Java', 'C++', 'Kotlin', 'Swift']
items.sort()
print(items)  # ['C++', 'Java', 'Kotlin', 'Python', 'Swift']
items.reverse()
print(items)  # ['Swift', 'Python', 'Kotlin', 'Java', 'C++']

▶ 运行结果:

输出
['C++', 'Java', 'Kotlin', 'Python', 'Swift']
['Swift', 'Python', 'Kotlin', 'Java', 'C++']

列表生成式
在 Python 中,列表还可以通过一种特殊的语法来创建,这种语法叫做生成式。

python
# 例一:创建一个取值范围在1到99且能被3或者5整除的数字构成的列表。
items = []
for i in range(1, 100):
    if i % 3 == 0 or i % 5 == 0:
        items.append(i)
print(items)

# 使用列表生成式做同样的事情,代码如下所示。
items = [i for i in range(1, 100) if i % 3 == 0 or i % 5 == 0]
print(items)

# 例二:有一个整数列表nums1,创建一个新的列表nums2,nums2中的元素是nums1中对应元素的平方。
nums1 = [35, 12, 97, 64, 55]
nums2 = []
for num in nums1:
    nums2.append(num ** 2)
print(nums2)

#  使用列表生成式做同样的事情
nums1 = [35, 12, 97, 64, 55]
nums2 = [num ** 2 for num in nums1]
print(nums2)

# 例三: 有一个整数列表nums1,创建一个新的列表nums2,将nums1中大于50的元素放到nums2中。
nums1 = [35, 12, 97, 64, 55]
nums2 = []
for num in nums1:
    if num > 50:
        nums2.append(num)
print(nums2)

# 使用列表生成式做同样的事情,代码如下所示。
nums1 = [35, 12, 97, 64, 55]
nums2 = [num for num in nums1 if num > 50]
print(nums2)

▶ 运行结果:

输出
[3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30, 33, 35, 36, 39, 40, 42, 45, 48, 50, 51, 54, 55, 57, 60, 63, 65, 66, 69, 70, 72, 75, 78, 80, 81, 84, 85, 87, 90, 93, 95, 96, 99]
[3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30, 33, 35, 36, 39, 40, 42, 45, 48, 50, 51, 54, 55, 57, 60, 63, 65, 66, 69, 70, 72, 75, 78, 80, 81, 84, 85, 87, 90, 93, 95, 96, 99]
[1225, 144, 9409, 4096, 3025]
[1225, 144, 9409, 4096, 3025]
[97, 64, 55]
[97, 64, 55]

嵌套列表
Python 语言没有限定列表中的元素必须是相同的数据类型,也就是说一个列表中的元素可以任意的数据类型,当然也包括列表本身。如果列表中的元素也是列表,那么我们可以称之为嵌套的列表。嵌套的列表可以用来表示表格或数学上的矩阵,例如:我们想保存5个学生3门课程的成绩,可以用如下所示的列表。

python
scores = [[95, 83, 92], [80, 75, 82], [92, 97, 90], [80, 78, 69], [65, 66, 89]]
print(scores[0])
print(scores[0][1])

▶ 运行结果:

输出
[95, 83, 92]
83

如果想通过产生随机数的方式来生成5个学生3门课程的成绩并保存在列表中,我们可以使用列表生成式,代码如下所示。

python
import random

scores = [[random.randrange(60, 101) for _ in range(3)] for _ in range(5)]
print(scores)

▶ 运行结果:

输出
[[60, 79, 90], [68, 62, 68], [89, 94, 72], [69, 71, 78], [60, 96, 79]]