Python语法(三)

目录

  • 前言:
  • 一:列表和元组
    • [1. 列表到底是什么](#1. 列表到底是什么)
    • [2. 如何创建列表](#2. 如何创建列表)
    • 3.下标访问:列表不是一坨,它是有位置的
    • [4. 下标越界:不是所有位置都能访问](#4. 下标越界:不是所有位置都能访问)
    • [5. 负数下标:从后往前数](#5. 负数下标:从后往前数)
    • [6. 切片:一次不是取一个,而是取一段](#6. 切片:一次不是取一个,而是取一段)
    • [7. 切片省略边界:从头切、切到尾、全切出来](#7. 切片省略边界:从头切、切到尾、全切出来)
    • [8. 切片步长:不是一个一个取,而是隔着取](#8. 切片步长:不是一个一个取,而是隔着取)
    • [9. 遍历列表:把元素一个一个拿出来处理](#9. 遍历列表:把元素一个一个拿出来处理)
    • [10. 新增元素:append 和 insert](#10. 新增元素:append 和 insert)
    • [11. 查找元素:in 和 index](#11. 查找元素:in 和 index)
    • [12. 删除元素:pop 和 remove](#12. 删除元素:pop 和 remove)
    • [13. 连接列表:+ 和 extend](#13. 连接列表:+ 和 extend)
    • [14. 元组:和列表很像,但它"不能改"](#14. 元组:和列表很像,但它“不能改”)
    • [15. 为什么明明有列表了,还要有元组](#15. 为什么明明有列表了,还要有元组)
    • [16. 函数返回多个值时,背后其实就是元组](#16. 函数返回多个值时,背后其实就是元组)
    • [17. 列表和元组到底怎么选](#17. 列表和元组到底怎么选)

前言:

前面学函数时,我们处理的大多是"一个变量对应一个值"。

但是实际写程序时,经常会遇到这种场景:

一个班几十个学生成绩

一堆商品价格

一串坐标点

一批文件名

这时候如果还写成:

python 复制代码
num1 = 10
num2 = 20
num3 = 30
...

就会非常笨重,
当数据个数很多,甚至个数都不确定时,就需要用列表来批量保存数据。 元组和列表很像,但元组一旦创建后内容不能改,而列表可以改。

就比如:

列表像袋子,随时能往里放、往外拿;元组像已经封装好的包装,里面多少就是多少

一:列表和元组

1. 列表到底是什么

你可以先把列表理解成:

Python 里用来按顺序存一批数据的容器。

这个理解非常重要。

它不是一个单独的数据,而是一串有顺序的数据。

比如:

python 复制代码
scores = [95, 88, 76, 100]

这个 scores 不是一个数字,而是一整个"序列"。

类比C++,可以把它先粗略类比成 vector。但要注意,Python 的列表比 C++ 的 vector 更灵活,列表里允许存放不同类型的元素。 也就是说,你甚至可以这么写:

python 复制代码
alist = [1, 'hello', True]

这在 Python 里是合法的。

但在 C++ 里,vector 通常要求元素类型一致,所以这也是 Python 动态类型很典型的体现。

2. 如何创建列表

两种最基础的创建方式:

python 复制代码
alist = []
alist = list()

这两种都表示创建一个空列表。

如果你想创建时直接放入初始值,就写到方括号里:

python 复制代码
alist = [1, 2, 3, 4]
print(alist)

注意:不要拿 list 当变量名,因为 list 本身是 Python 的内建函数

这这就像在 C++ 里最好别拿 string、vector 这些名字去乱当变量名,不然可读性会变差,甚至引发冲突。

3.下标访问:列表不是一坨,它是有位置的

列表里的元素是有顺序的,所以每个元素都有自己的位置。

这里把这个位置叫做 下标 或 索引

注意:Python 列表下标从 0 开始

比如:

python 复制代码
alist = [1, 2, 3, 4]
print(alist[2])

这里输出的不是 2,而是 3。

因为:

alist0 是 1

alist1 是 2

alist2 是 3

这和 C++ 数组、vector 的下标规则是一致的。

更重要的是:下标不只是能读,还能改。 比如:

python 复制代码
alist = [1, 2, 3, 4]
alist[2] = 100
print(alist)

执行后列表变成:

python 复制代码
[1, 2, 100, 4]

这说明列表是可变对象,这也是它和元组最大的区别之一。

4. 下标越界:不是所有位置都能访问

一个常见错误:如果下标超出列表有效范围,会抛异常

比如:

python 复制代码
alist = [1, 2, 3, 4]
print(alist[100])

这会报 IndexError: list index out of range

原因很简单:列表里根本没有第 101 个元素。

说明:
如果列表长度是 len(alist),那么有效下标范围就是 0, len(alist)-1

例如:

python 复制代码
alist = [1, 2, 3, 4]
print(len(alist))   # 4

那它的合法下标就是:

python 复制代码
0 1 2 3

5. 负数下标:从后往前数

这个是 Python 很方便的地方=:下标可以取负数,表示倒数第几个元素。

例如:

python 复制代码
alist = [1, 2, 3, 4]
print(alist[-1])

因为:

-1 表示倒数第一个

-2 表示倒数第二个

-3 表示倒数第三个

对应关系:

alist-1 等价于 alistlen(alist)-1

这个在实际开发里非常好用。

比如你想拿最后一个元素,C++ 常见写法可能是 vecvec.size() - 1,而 Python 直接 alist-1,又短又直观。

6. 切片:一次不是取一个,而是取一段

前面的下标访问,一次拿一个元素。 切片,它的本质是:

一次取出一组连续元素,得到一个子列表。

最基础写法:

python 复制代码
alist = [1, 2, 3, 4]
print(alist[1:3])

结果是:

这里特别容易踩坑,所以必须讲清楚:

1:3 表示的是 前闭后开区间 [1, 3)。

也就是:

包含下标 1

包含下标 2

不包含下标 3

所以最后得到 2 和 3,而不是 2、3、4。

并且:+ Python 里很多地方都在用"前闭后开"这个思想。

7. 切片省略边界:从头切、切到尾、全切出来

课件继续讲了切片边界可以省略。

比如:

python 复制代码
alist = [1, 2, 3, 4]

print(alist[1:])   # 从下标1取到末尾
print(alist[:-1])  # 从开头取到倒数第一个之前
print(alist[:])    # 取整个列表

结果大概是:

![2, 3, 4

1, 2, 3

1, 2, 3, 4](https://i-blog.csdnimg.cn/direct/23c578e107ee442e9dfd2212443fcbb2.png)

这里的规律其实很简单:

左边不写,默认从头开始
右边不写,默认取到末尾
两边都不写,就是完整复制一份当前列表

所以你以后看到 :,脑子里就要立刻想到:

这是在"把整个序列切出来"。

8. 切片步长:不是一个一个取,而是隔着取

切片还能写第三个参数,表示 步长。

例如:

python 复制代码
alist = [1,2,3,4,5,6,7,8,9,10]

print(alist[::1])
print(alist[::2])
print(alist[::3])

大概可以理解为:

::1 表示一个一个取

::2 表示隔一个取一个

::3 表示每隔两个取一个

这就像你走楼梯:

步长 1:一级一级走

步长 2:两级两级跳

步长 3:三级三级跳

并且:步长可以是负数,这就表示从后往前取。

例如:

python 复制代码
alist = [1,2,3,4,5,6,7,8,9,10]

print(alist[::-1])

这就是反转列表,结果是:

python 复制代码
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

这个写法很经典,以后你会经常看到。

还有一个很 Python 的细节:切片数字越界一般不会报错,只会尽可能拿到满足条件的元素。 比如课件里有 alist100:200,结果不是异常,而是空列表 \[\]。

所以要记住:

单个下标越界:报错

切片越界:通常不报错,尽量给结果

9. 遍历列表:把元素一个一个拿出来处理

把元素一个一个取出来,再分别处理。

最常见的遍历方式是 for:

python 复制代码
alist = [1, 2, 3, 4]
for elem in alist:
    print(elem)

这个是最推荐的基础写法,因为简单直接。

但是Python 还给了两种变体。

第一种,用下标遍历:

python 复制代码
alist = [1, 2, 3, 4]
for i in range(0, len(alist)):
    print(alist[i])

第二种,用 while 手动控制下标

python 复制代码
alist = [1, 2, 3, 4]
i = 0
while i < len(alist):
    print(alist[i])
    i += 1

这三种都能遍历,但在日常开发中:

只关心元素本身,用 for elem in alist

既想要下标又想要元素,再考虑别的写法

10. 新增元素:append 和 insert

append:它表示 尾插,也就是把新元素加到列表最后面。

python 复制代码
alist = [1, 2, 3, 4]
alist.append('hello')
print(alist)

结果:

如果你不想加到最后,而是想插到中间某个位置,就用 insert:insert 的第一个参数是插入位置的下标。

python 复制代码
alist = [1, 2, 3, 4]
alist.insert(1, 'hello')
print(alist)

结果:

这里你可以这样理解:

append:直接加尾巴
insert:指定位置塞进去

11. 查找元素:in 和 index

第一个是 in,判断某个元素在不在列表里,返回布尔值:

python 复制代码
alist = [1, 2, 3, 4]
print(2 in alist)
print(10 in alist)

结果大概是:

python 复制代码
True
False

第二个是 index,找某个元素第一次出现的位置:

python 复制代码
alist = [1, 2, 3, 4]
print(alist.index(2))

结果是:

python 复制代码
1

因为 2 在下标 1 的位置。

但你一定要小心一个坑:如果元素不存在,index 会抛异常。

python 复制代码
alist = [1, 2, 3, 4]
print(alist.index(10))   # 报错

所以实际写代码时,通常更稳一点的思路是:

先用 in 判断

再决定要不要 index

这就是"先试探,再深入"。

12. 删除元素:pop 和 remove

pop():按位置删

python 复制代码
alist = [1, 2, 3, 4]
alist.pop()
print(alist)

结果:

python 复制代码
[1, 2, 3]

这表示删除最后一个元素。

注意:pop 也可以带下标,表示删指定位置的元素。

python 复制代码
alist = [1, 2, 3, 4]
alist.pop(2)
print(alist)

结果:

python 复制代码
[1, 2, 4]

remove():按值删

python 复制代码
alist = [1, 2, 3, 4]
alist.remove(2)
print(alist)

结果:

python 复制代码
[1, 3, 4]

这次删掉的是"值为 2 的元素",不是"下标为 2 的元素"。

所以这里特别容易混:

pop(2):删的是第 3 个位置上的元素
remove(2):删的是值等于 2 的元素

13. 连接列表:+ 和 extend

两个"拼接列表"的方式:

先看 +:

alist = 1, 2, 3, 4
blist = 5, 6, 7
print(alist + blist)

结果:

但要注意 :

+ 会生成一个新的列表,不会修改旧列表。

也就是说,alist 自己没变,blist 也没变,只是临时拼出来一个新结果。

再看 extend:

python 复制代码
alist = [1, 2, 3, 4]
blist = [5, 6, 7]
alist.extend(blist)
print(alist)
print(blist)

执行后:

alist 会变成 1,2,3,4,5,6,7

blist 还是 5,6,7

a.extend(b) 是把 b 的内容接到 a 的末尾,不改 b,但会改 a。

所以这里的区别就是:

+:生成新列表
extend:原地扩展原列表

14. 元组:和列表很像,但它"不能改"

最核心的一句话就是:元组和列表功能基本一致,但元组里的元素不能修改。

元组用小括号表示:

python 复制代码
atuple = ()
atuple = tuple()

它和列表的关系,你可以这样理解:

列表:可变序列
元组:不可变序列

像这些"读操作"元组也支持:

下标访问
切片
遍历
in
index
+

但是这些"写操作"元组不支持:

修改元素
新增元素
删除元素
extend

所以元组不是"功能差的列表",而是"更稳定、更安全的列表"。

15. 为什么明明有列表了,还要有元组

1.第一层原因:安全

如果你有一组数据,不希望它被函数随手改乱,那么传元组会更稳。

因为列表可变,函数拿到以后可能改内容;元组不可变,别人想改也改不了。意思就是:当你不确定某个函数会不会把数据弄乱时,传元组更安全。

2.第二层原因:元组可以当字典的键

字典的键要求是 可 hash 的对象,而"可 hash"的一个重要前提就是"不可变"。于是:

元组可以作为字典的键

列表不行

这也是元组存在的重要工程意义。

16. 函数返回多个值时,背后其实就是元组

这个点和你前面学函数正好连起来。

当一个函数返回多个值时,很多时候默认得到的其实是元组。

例如:

python 复制代码
def getPoint():
    return 10, 20

result = getPoint()
print(type(result))

输出类型其实是:

python 复制代码
<class 'tuple'>

所以你之前看到这种写法:

python 复制代码
x, y = getPoint()

本质上就是:

getPoint() 返回了一个元组 (10, 20)

17. 列表和元组到底怎么选

你可以把它总结成一句话:

需要改,用列表;不需要改,用元组。

再展开一点就是:

只要你表示的是一串有顺序的数据,都可以考虑列表/元组

如果后续要增删改,优先列表

如果数据是固定的、不想被改,优先元组

例如:

适合列表:学生成绩后续还会录入、修改

python 复制代码
scores = [90, 88, 76]

适合元组:一个点的坐标通常就是固定的

python 复制代码
point = (10, 20)
相关推荐
满怀冰雪1 分钟前
01_LangChain是什么_带你理解LLM应用框架
python·langchain
稷下元歌13 分钟前
python核心基础,这关于基于Moveltg加 Ros2实战Python编程基础实课
开发语言·python
AI人工智能+电脑小能手20 分钟前
【大白话说Java面试题 第114题】【并发篇】第14题:说一下悲观锁的优点和缺点?
java·开发语言·面试
财经资讯数据_灵砚智能20 分钟前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年6月10日
大数据·人工智能·python·ai·信息可视化·自然语言处理·灵砚智能
盒马盒马22 分钟前
Rust:Vec
开发语言·rust
Wonderful U23 分钟前
Python+Django实战|企业客户关系管理系统(CRM):客户档案、跟进记录、商机管理、合同签约、回款追踪、客户分层、数据分析
python·数据分析·django
Wonderful U23 分钟前
Python+Django实战|企业办公用品申领管理系统:物资入库、库存预警、申领审批、归还登记、损耗统计、供应商对账
android·python·django
devilnumber24 分钟前
Java 迭代器(Iterator)完全指南:从入门到实战
java·开发语言·迭代器
罗超驿26 分钟前
13.Java多线程进阶:手动实现线程池与定时器机制详解
开发语言·面试·javaee
弹简特30 分钟前
【Java项目-轻聊】10-实现会话管理模块
java·开发语言·数据库