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。

因为:

alist[0] 是 1

alist[1] 是 2

alist[2] 是 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] 等价于 alist[len(alist)-1]。

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

比如你想拿最后一个元素,C++ 常见写法可能是 vec[vec.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 的细节:切片数字越界一般不会报错,只会尽可能拿到满足条件的元素。 比如课件里有 alist\[100: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) ``` 结果: ![\[1, 2, 3, 4, 'hello'\]](https://i-blog.csdnimg.cn/direct/6548d42e1ca04d47a72fec1c9cdf72a7.png) 如果你不想加到最后,而是想插到中间某个位置,就用 insert:**insert 的第一个参数是插入位置的下标。** ```python alist = [1, 2, 3, 4] alist.insert(1, 'hello') print(alist) ``` 结果: ![\[1, 'hello', 2, 3, 4\]](https://i-blog.csdnimg.cn/direct/8153421d6e34440cb4d656f0da314782.png) 这里你可以这样理解: **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)) # 报错 ``` ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/94a39fac589c4ba6960e0d3637cb1a00.png) 所以实际写代码时,通常更稳一点的思路是: 先用 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)
相关推荐
likerhood11 小时前
Java 异常处理:从 try-catch-finally 到项目最佳实践
java·开发语言·php
松☆12 小时前
10分钟上手pypto:用Python直接调PTO虚拟指令集
开发语言·python
并不喜欢吃鱼12 小时前
从零开始 C++----十【C++ 数据结构】AVL 树详解:从原理到实现
开发语言·数据结构·c++
晚烛12 小时前
CANN 大模型推理优化实战:FlashAttention、推测解码与连续批处理的工程实现
开发语言·人工智能·python·深度学习·数据挖掘
sycmancia12 小时前
Qt——发送自定义事件(下)
开发语言·qt
*愿风载尘*12 小时前
Python多重继承MRO报错问题处理
开发语言·python
子午12 小时前
基于YOLO的PCB电路板缺陷检测系统~Python+目标检测+深度学习+YOLOV8算法+模型训练+人工智能
人工智能·python·yolo
yqcoder12 小时前
数据的“洁癖”管家:深入解析 JavaScript Set
开发语言·javascript·ecmascript
码界筑梦坊12 小时前
144-基于Flask的电商超市数据可视化分析系统
开发语言·python·信息可视化·数据分析·flask