上一章讲完循环以后,我们已经可以重复处理一组数据了。不过,前面的例子大多使用字符串或者 range(),真正写程序时,还需要把多个数据放在一起保存。例如,一组商品名称、一批考试成绩,或者一个坐标中的多个数值。
python 中最常用的两种序列类型是列表和元组。列表可以在创建后继续增加、删除和修改元素,元组创建以后不能直接修改。这一章会把它们的创建、索引、切片、常用操作、复制以及打包和解包讲清楚。

一、创建列表
列表使用方括号 [] 创建,元素之间使用逗号分隔:
languages = ["python", "java", "go"] scores = [95, 88, 76]
列表中的元素按照写入顺序保存,同一个列表也可以放入不同类型的数据:
user = ["ivan", 20, true]
这种写法语法上没有问题。不过,如果列表中的元素完全没有统一含义,后面的代码会比较难处理。大多数情况下,一个列表会保存同一类数据。
空列表可以写成:
items = []
也可以使用 list() 创建:
items = list()
list() 还可以把其他可迭代对象转换成列表:
letters = list("python")
numbers = list(range(1, 6))
print(letters)
print(numbers)输出结果为:
['p', 'y', 't', 'h', 'o', 'n'] [1, 2, 3, 4, 5]
len() 可以取得列表中的元素数量:
languages = ["python", "java", "go"] print(len(languages))
结果为 3。
二、通过索引访问元素
列表和字符串一样,索引从 0 开始:
languages = ["python", "java", "go"] print(languages[0]) print(languages[1]) print(languages[2])
输出结果为:
python java go
负数索引从列表末尾开始计算,-1 表示最后一个元素:
print(languages[-1]) print(languages[-2])
输出结果为:
go java
访问不存在的位置会出现 indexerror:
print(languages[3])
如果列表可能为空,不能直接访问 items[0]。可以先判断列表中是否有内容:
items = []
if items:
print(items[0])
else:
print("列表为空")三、列表切片
切片可以从列表中取出一段数据,写法与字符串相同:
列表[开始位置:结束位置:步长]
切片包含开始位置,不包含结束位置:
letters = ["p", "y", "t", "h", "o", "n"] print(letters[1:4])
输出结果为:
['y', 't', 'h']

开始位置和结束位置都可以省略:
numbers = [0, 1, 2, 3, 4, 5] print(numbers[:3]) print(numbers[3:]) print(numbers[:])
输出结果为:
[0, 1, 2] [3, 4, 5] [0, 1, 2, 3, 4, 5]
第三个参数表示步长:
print(numbers[::2]) print(numbers[::-1])
输出结果为:
[0, 2, 4] [5, 4, 3, 2, 1, 0]
切片返回的是一个新列表。修改切片得到的结果,不会直接改变原列表:
numbers = [10, 20, 30, 40] part = numbers[1:3] part[0] = 200 print(numbers) print(part)
输出结果为:
[10, 20, 30, 40] [200, 30]
这里先讨论一层列表。列表中还包含其他列表时,复制关系会复杂一些,后面会单独说明。
四、修改列表中的元素
字符串和元组创建以后不能直接修改,列表可以。给某个索引重新赋值,就能替换这个位置的元素:
languages = ["python", "java", "go"] languages[1] = "rust" print(languages)
输出结果为:
['python', 'rust', 'go']
也可以使用切片一次替换多个元素:
numbers = [1, 2, 3, 4, 5] numbers[1:4] = [20, 30] print(numbers)
输出结果为:
[1, 20, 30, 5]
右侧元素的数量不必和被替换的数量相同,所以切片赋值也可能改变列表长度。

五、向列表中添加元素
1.append()在末尾添加一个元素
languages = ["python", "java"]
languages.append("go")
print(languages)输出结果为:
['python', 'java', 'go']
append() 每次只添加一个元素。如果传入的是一个列表,整个列表会作为一个元素放进去:
numbers = [1, 2] numbers.append([3, 4]) print(numbers)
输出结果为:
[1, 2, [3, 4]]
2.extend()一次添加多个元素
extend() 会依次取出可迭代对象中的元素,再添加到原列表末尾:
numbers = [1, 2] numbers.extend([3, 4]) print(numbers)
输出结果为:
[1, 2, 3, 4]
append([3, 4]) 会增加一个列表元素,extend([3, 4]) 会增加两个整数元素,这两种结果不要混在一起。

extend() 也可以接收字符串,不过它会把字符串逐个拆成字符:
letters = ["a"]
letters.extend("bc")
print(letters)结果为 ['a', 'b', 'c']。
3.insert()在指定位置插入
languages = ["python", "go"] languages.insert(1, "java") print(languages)
输出结果为:
['python', 'java', 'go']
insert(1, "java") 表示把 java 放到索引 1,原来位于这个位置及其后面的元素会向后移动。
六、删除列表中的元素
1. 使用del按索引删除
languages = ["python", "java", "go"] del languages[1] print(languages)
del 也可以删除一段切片:
numbers = [0, 1, 2, 3, 4, 5] del numbers[1:4] print(numbers)
输出 [0, 4, 5]。
2.remove()按值删除
languages = ["python", "java", "go"]
languages.remove("java")
print(languages)列表中存在多个相同元素时,remove() 只删除第一个:
numbers = [10, 20, 10, 30] numbers.remove(10) print(numbers)
输出 [20, 10, 30]。
删除不存在的值会出现 valueerror。如果这是一种正常情况,可以先使用 in 判断:
if "java" in languages:
languages.remove("java")
3.pop()删除并返回元素
pop() 默认取出最后一个元素:
languages = ["python", "java", "go"] last_language = languages.pop() print(last_language) print(languages)
输出结果为:
go ['python', 'java']
也可以传入索引:
language = languages.pop(0)
remove() 根据值删除,并且不返回被删除的元素;pop() 根据索引删除,并返回被删除的元素。

4.clear()清空列表
languages = ["python", "java", "go"] languages.clear() print(languages)
结果为 []。
七、查找、统计与成员判断
in 和 not in 可以判断列表中是否包含某个元素:
languages = ["python", "java", "go"]
print("python" in languages)
print("rust" not in languages)index() 返回指定元素第一次出现的位置:
print(languages.index("java"))
结果为 1。元素不存在时,index() 会出现 valueerror。
count() 用来统计元素出现的次数:
numbers = [10, 20, 10, 30, 10] print(numbers.count(10))
结果为 3。
数值列表还可以使用 min()、max() 和 sum():
scores = [86, 92, 75, 98] print(min(scores)) print(max(scores)) print(sum(scores)) print(sum(scores) / len(scores))
最后一行计算平均值。列表为空时不能直接相除,需要先判断 len(scores) 是否大于 0。
八、列表排序与反转
1.sort()修改原列表
numbers = [30, 10, 40, 20] numbers.sort() print(numbers)
输出结果为:
[10, 20, 30, 40]
降序排列可以设置 reverse=true:
numbers.sort(reverse=true)
sort() 会直接修改原列表,并且返回 none。不要写成:
# 错误用法 result = numbers.sort()
这时 result 得到的是 none,不是排序后的列表。
2.sorted()返回新列表
numbers = [30, 10, 40, 20] result = sorted(numbers) print(numbers) print(result)
输出结果为:
[30, 10, 40, 20] [10, 20, 30, 40]
原列表需要保留时使用 sorted(),允许直接改变原列表时可以使用 sort()。

3. 使用key指定排序规则
words = ["banana", "kiwi", "apple"] words.sort(key=str.lower) print(words)
这里排序时会先按每个字符串的小写结果比较,所以不会直接受到原始大小写顺序影响。
reverse() 只负责把现有顺序反过来,并不进行大小排序:
numbers = [10, 30, 20] numbers.reverse() print(numbers)
结果为 [20, 30, 10],不是降序排列。
九、遍历列表
前面已经学过 for 循环,可以直接依次取出列表中的元素:
languages = ["python", "java", "go"]
for language in languages:
print(language)需要同时取得索引时,使用 enumerate():
for index, language in enumerate(languages, start=1):
print(index, language)
输出结果为:
1 python 2 java 3 go
遍历列表时直接删除其中的元素,可能跳过数据:
numbers = [1, 2, 3, 4]
for number in numbers:
if number % 2 == 0:
numbers.remove(number)需要筛选数据时,更稳妥的方式是生成一个新列表:
numbers = [1, 2, 3, 4]
result = []
for number in numbers:
if number % 2 != 0:
result.append(number)
print(result)下一章后面还会单独讲列表推导式,到时候可以把这段筛选写得更简洁。
十、列表赋值与复制
下面的代码并没有创建两个列表:
a = [10, 20, 30] b = a b.append(40) print(a) print(b)
输出结果为:
[10, 20, 30, 40] [10, 20, 30, 40]
b = a 只是让两个变量指向同一个列表对象,所以通过 b 修改列表,a 看到的内容也会变化。
需要复制一层列表时,可以使用 copy():
a = [10, 20, 30] b = a.copy() b.append(40) print(a) print(b)
输出结果为:
[10, 20, 30] [10, 20, 30, 40]

完整切片也能创建一个新的一层列表:
b = a[:]
不过,copy() 和切片都只复制列表的外层。如果列表里面还放着其他可变对象,内层对象仍然可能被两个列表共同引用:
a = [[1, 2], [3, 4]] b = a.copy() b[0].append(100) print(a) print(b)
两个结果中的第一个内层列表都会出现 100。这一章先记住这个现象,可变对象、不可变对象、浅拷贝和深拷贝会放到后面的专门章节中详细讲。
十一、嵌套列表
列表中的元素还可以是列表,这种结构称为嵌套列表:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]访问元素时需要使用两次索引:
print(matrix[0]) print(matrix[0][1])
输出结果为:
[1, 2, 3] 2
第一个索引选择外层列表中的一行,第二个索引再选择这一行中的元素。
可以使用嵌套循环遍历:
for row in matrix:
for number in row:
print(number, end=" ")
print()创建重复的嵌套列表时,不要直接写:
# 容易出问题的写法 rows = [[0, 0, 0]] * 3
这三行会引用同一个内层列表。修改一行时,其他行也会一起变化:
rows[0][0] = 1 print(rows)
应该让每一行分别创建:
rows = []
for _ in range(3):
rows.append([0, 0, 0])推导式章节会再介绍更简洁的创建方式。
十二、创建元组
元组使用圆括号 () 创建:
point = (10, 20)
languages = ("python", "java", "go")
空元组可以写成:
empty_tuple = ()
只有一个元素的元组必须保留逗号:
value1 = (10) value2 = (10,) print(type(value1)) print(type(value2))
输出结果为:
<class 'int'> <class 'tuple'>
决定它是不是元组的是逗号,不是圆括号。圆括号只是让结构更容易看清。

也可以使用 tuple() 转换其他可迭代对象:
numbers = tuple([10, 20, 30])
letters = tuple("abc")
print(numbers)
print(letters)十三、访问和切片元组
元组同样是有顺序的,所以索引和切片写法与列表相同:
languages = ("python", "java", "go")
print(languages[0])
print(languages[-1])
print(languages[0:2])输出结果为:
python
go
('python', 'java')元组切片得到的仍然是元组。
len()、in、not in、index() 和 count() 也可以用于元组:
numbers = (10, 20, 10, 30) print(len(numbers)) print(20 in numbers) print(numbers.index(20)) print(numbers.count(10))
十四、元组不能直接修改
元组创建以后,不能替换、增加或者删除其中的元素:
point = (10, 20) # typeerror point[0] = 100
元组没有 append()、remove() 和 pop() 这些会改变内容的方法。
如果确实需要改变,可以转换成列表,修改后再转回元组:
point = (10, 20) values = list(point) values[0] = 100 point = tuple(values) print(point)
不过,如果数据经常需要修改,一开始就使用列表会更合适。
元组本身不能修改,不代表它里面的所有对象都不能修改。例如,元组中包含列表时,仍然可以修改这个列表的内容:
data = ("scores", [80, 90])
data[1].append(100)
print(data)输出结果为:
('scores', [80, 90, 100])
不能改变的是元组中保存的引用位置,内层列表仍然是可变对象。
十五、元组的打包与解包
把多个值放进一个元组称为打包:
user = "ivan", 20, "python" print(user)
输出结果为:
('ivan', 20, 'python')
把元组中的值分别交给多个变量称为解包:
name, age, language = user print(name) print(age) print(language)

普通解包时,变量数量必须和元素数量一致,否则会出现 valueerror。
不需要其中某个值时,通常使用下划线接收:
name, _, language = user
星号变量可以接收剩余的多个元素,结果会是列表:
numbers = (10, 20, 30, 40, 50) first, *middle, last = numbers print(first) print(middle) print(last)
输出结果为:
10 [20, 30, 40] 50
交换变量时使用的写法,本质上也会用到打包和解包:
a = 10 b = 20 a, b = b, a
十六、列表与元组之间转换
list() 可以把元组转换成列表,tuple() 可以把列表转换成元组:
languages_tuple = ("python", "java", "go")
languages_list = list(languages_tuple)
scores_list = [90, 85, 96]
scores_tuple = tuple(scores_list)
print(languages_list)
print(scores_tuple)转换会创建新的外层对象,不会把原对象直接变成另一种类型。
十七、列表和元组怎么选
列表和元组都是有顺序的序列,也都支持索引、切片和循环遍历。区别主要在于数据创建以后是否需要改变。
| 对比项 | 列表 list | 元组 tuple |
|---|---|---|
| 写法 | [1, 2, 3] | (1, 2, 3) |
| 是否有顺序 | 有 | 有 |
| 能否修改元素 | 可以 | 不可以 |
| 能否增删元素 | 可以 | 不可以 |
| 常见用途 | 需要持续变化的一组数据 | 创建后保持固定的一组数据 |
商品列表、任务列表和用户输入记录通常会不断变化,适合使用列表。坐标、rgb 颜色值和函数一次返回的多个固定结果,可以使用元组。
不需要为了“性能更高”把所有列表都改成元组。首先应该根据数据是否需要修改来选择,代码含义清楚更重要。
十八、综合示例:整理学生成绩
下面使用列表保存多名学生,每名学生的信息使用元组表示。程序会过滤无效成绩,再按照分数从高到低排序:
records = [
("张三", 86),
("李四", 95),
("王五", 72),
("赵六", 105),
]
valid_records = []
for name, score in records:
if score < 0 or score > 100:
print(f"忽略无效成绩:{name} {score}")
continue
valid_records.append((name, score))
valid_records.sort(key=lambda item: item[1], reverse=true)
print("成绩排名:")
for rank, (name, score) in enumerate(valid_records, start=1):
print(f"{rank}. {name}:{score}")输出结果为:
忽略无效成绩:赵六 105 成绩排名: 1. 李四:95 2. 张三:86 3. 王五:72
外层使用列表,是因为学生记录可能继续增加或删除。每条记录使用元组,是因为姓名和成绩在这次排序过程中作为一条完整记录处理。
排序中的 lambda item: item[1] 表示取出每条记录索引为 1 的成绩作为排序依据。匿名函数会在后面的函数章节中详细讲,这里先看懂它负责“按成绩排序”即可。
十九、常见错误
1. 索引超出范围
items = [10, 20, 30] print(items[3])
有效索引只有 0、1 和 2。
2. 混淆append()和extend()
items = [1, 2] items.append([3, 4])
结果是 [1, 2, [3, 4]]。如果需要 [1, 2, 3, 4],应该使用 extend()。
3. 接收sort()的返回值
numbers = [3, 1, 2] numbers = numbers.sort()
执行以后 numbers 会变成 none。sort() 直接修改原列表,不返回排序后的列表。
4. 误以为赋值会复制列表
b = a
这只会增加一个指向同一列表的变量。需要复制一层列表时,可以使用 a.copy()。
5. 忘记单元素元组的逗号
value = (10)
这仍然是整数。单元素元组应该写成 (10,)。
6. 解包数量不一致
point = (10, 20, 30) x, y = point
三个元素不能直接交给两个普通变量。可以增加变量,或者使用星号变量接收剩余内容。
7. 使用乘法创建嵌套列表
rows = [[0, 0]] * 3
三个位置引用的是同一个内层列表,修改其中一行会影响其他行。
二十、练习
练习一:管理待办事项
创建一个待办列表,依次完成添加任务、修改任务、删除任务和输出全部任务。
练习二:统计成绩
给定一个成绩列表,输出最高分、最低分、总分和平均分,并统计 60 分以下的成绩有多少个。
练习三:列表去重
给定列表 [1, 2, 2, 3, 1, 4],在不使用集合的情况下,生成一个不包含重复元素的新列表,并保留原来的出现顺序。
练习四:排序商品
使用元组保存商品名称和价格,再把多条商品记录放进列表中,按照价格从低到高输出。
练习五:矩阵转置
给定一个三行三列的嵌套列表,使用嵌套循环把行和列交换,生成一个新的列表。
这一章把列表和元组的常用操作讲完了。下一章继续学习字典与集合,字典通过键保存和查找数据,集合更适合处理不重复元素以及交集、并集和差集。
到此这篇关于python基础语法之列表与元组的文章就介绍到这了,更多相关python 列表与元组内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论