Python基础语法学习

目录

1 先把环境跑起来

检查项 命令 正常结果 如果报错了怎么办?
Python 有没有装好 python --version Python 3.11.9 之类 提示“不是内部或外部命令”→ 把 Python 加入系统 PATH
pip 能不能用 python -m pip --version pip 24.0 … 提示 upgrade → 照它说的 python -m pip install -U pip
能不能建虚拟环境 python -m venv venv 出现 venv 文件夹 提示缺少 ensurepip → Ubuntu 用 sudo apt install python3-venv

第一个小程序

把下面 3 行新建成 hello.py,双击或者 python hello.py 能跑就行。

1
2
# 文件:hello.py
print("数据采集入门") # 双引号、单引号都行;这句话会在小黑框里出现

拆给你看

  • print() 是 Python 自带的“扩音器”,括号里写什么就往外吐什么。
  • 字符串可以用单引号 ' '、双引号 " "、三引号 ''' ''' 包裹,效果一样。
  • 行首的 # 叫“单行注释”,机器会无视,写给人类看的。
  • 多行注释用三引号 '''""" 包起来,常用来写函数说明书(docstring)。

2 基础语法结构

2.1 代码长什么样才好看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# ① 缩进用 4 个空格,不要 Tab 和空格混用
if True:# 条件为真
	print("缩进 4 空格")# 这句必须缩进,否则报错

# ② 注释写法
# 这是单行注释
'''
这是
多行注释
'''

小白注意 Python 用“缩进”当大括号 { },只要缩进不对就直接报 IndentationError

2.2 变量与数据类型

1
2
3
4
5
6
7
url = "https://example.com" # 字符串 str
page_count = 100# 整数 int,想多大就多大,不会溢出
is_crawling = True# 布尔 bool,只有 True/False 两个值

print(type(url))# <class 'str'>
print(type(page_count)) # <class 'int'>
print(type(is_crawling))# <class 'bool'>

拆给你看

  • 变量名第一次出现时就被“贴”上数据,不需要提前声明。
  • type() 相当于“照妖镜”,能看出变量到底是什么类型。

3 最常用的“容器”——字符串、列表、字典、元组、集合

3.1 字符串(str)

字符串是 Python 里一切文本的“万能容器”:存文字、传信息、拼格式、做清洗,既能当数据,又能当接口,让人与程序、程序与程序之间用“人话”无缝沟通。

一、查:有没有、在哪、多少次

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
s = "hello python, python!"

#  有没有
print('python' in s)         # True

# 2 第一次/最后一次出现的位置
print(s.find('python'))      # 6   (找不到返回 -1)
print(s.index('python'))     # 6   (找不到抛异常)

# 3. 出现次数
print(s.count('python'))     # 2

【课堂小练习】

目标:用 in / find / index / count 快速完成「有无-定位-计数」三连问。

案例 1:邮箱格式快检

原始数据:email = "user.name@example.com"

任务:

  1. 判断是否同时包含 @.
  2. 找出 @ 第一次出现的位置;
  3. 统计 . 在字符串里共出现几次。

二、改:大小写、去垃圾、替换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
s = "  Python  "

#  大小写
print(s.upper())             # '  PYTHON  '
print(s.lower())             # '  python  '
print(s.title())             # '  Python  '   每个单词首字母大写

# 2. 去空格/指定字符
print(s.strip())             # 'Python'   首尾空格全去掉
print(s.lstrip())            # 'Python  ' 只去左边
print(s.rstrip())            # '  Python' 只去右边

# 3. 替换
url = "https://old.com/api"
new = url.replace("old", "new")
print(new)                   # https://new.com/api

【课堂小练习】

目标:用「大小写 + 去空格 + 替换」组合技,一键把「用户手抖输入」变成「标准字段」。

案例1:收货地址标准化

原始数据:addr = " beiJing Old-STREET #8-2-502 "

任务:

  1. 去掉首尾空格;
  2. # 替换成「号」;
  3. 其余部分全转小写,再把每个单词首字母大写(即 title());
  4. 最终得到标准地址:Beijing Old-Street 号8-2-502

要求:不允许手动拼串,必须纯靠字符串方法。


三、切 & 接:split、join、切片

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
csv_line = "Alice,23,USA"

#  字符串 → 列表
lst = csv_line.split(",")
print(lst)                   # ['Alice', '23', 'USA']

# 2. 列表 → 字符串
again = "-".join(lst)
print(again)                 # Alice-23-USA

# 3. 切片(同列表,左闭右开)
date = "2025-08-07"
print(date[:4])              # '2025'
print(date[5:7])             # '08'

# 4. 字符串拼接(使用 + 运算符)
name = lst[0]
age  = lst[1]
country = lst[2]
info = name + " is " + age + " years old, from " + country + "."
print(info)                  # Alice is 23 years old, from USA.

【课堂小练习】

目标:用「 split → join → 切片 」三步法,把“一行杂合数据”拆干净再拼成“想要的样子”。

案例:订单快照格式化

原始数据:order = "20250909,MacBook Air,MGN63CH/A,¥8999,2"

任务:

  1. 以逗号拆分,得到各字段列表;
  2. 取出日期,并切片成年/月/日三部分,用 / 拼回:2025/09/09
  3. 把商品名与型号用「 - 」连接,形成短描述:MacBook Air-MGN63CH/A
  4. 计算小计(单价 × 数量),最后按「日期 | 短描述 | 小计」格式用「 | 」拼成新字符串输出。

预期结果: 2025/09/09 | MacBook Air-MGN63CH/A | ¥17998

要求:全程不允许手动写死任何字段,必须基于 split 结果动态取; 每个任务完成之后,都需要输出变量的值。

四、格式化的 3 种主流写法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
name, age = "Alice", 18

# 1. % 格式化(老派)
print("姓名:%s,年龄:%d" % (name, age))

# 2. format 格式化(中间派)
print("姓名:{},年龄:{}".format(name, age))

# 3. f-string 格式化(最新最推荐)
print(f"姓名:{name},年龄:{age},明年 {age + 1} 岁")

【课堂小练习】

目标:用「% → str.format → f-string」三种写法中的任意一种写法,把「商品单价、数量、折扣」算出的「实付金额」格式化输出。


案例:购物车小票

原始数据:

1
2
3
4
product = "AirPods Pro"
unit_price = 1999
quantity = 2
discount = 0.85          # 8.5 折

任务:

  1. 计算实付:unit_price * quantity * discount
  2. 格式化方式输出一行文字,参考输出:
    1
    
    商品:AirPods Pro,数量:2,实付:3398.30 元

要求:实付保留 2 位小数。

3.2 列表(list)

列表是 Python 的“百变收纳盒”:按序装任何东西,随时增删改排,用一条索引就能瞬间取出,让一堆数据既听话又好找。

一、创建与查看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#  1. 字面量直接造
lst1 = [1, 2, 3]

# 2. 空列表 & 追加
lst2 = []
lst2.append('a')          # 末尾加 1 个元素
print(lst2)               # ['a']

# 3. range 转列表
lst3 = list(range(5))     # [0, 1, 2, 3, 4]

# 4. 长度
print(len(lst3))          # 5

二、增:4 种添加方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
lst = [10, 20]

# 1. 尾部加一个元素
lst.append(30)
print(lst)                # [10, 20, 30]

# 2. 尾部加一堆元素(合并)
lst.extend([40, 50])
print(lst)                # [10, 20, 30, 40, 50]

# 3. 指定位置插入
lst.insert(1, 15)         # 索引 1 处插入 15
print(lst)                # [10, 15, 20, 30, 40, 50]

【课堂小练习】

目标:考察学生对列表追加、扩展与定点插入三种常用修改操作的区分与灵活运用。

任务:

  1. 定义一个列表,包含三个元素102030
  2. 在尾部添加一个元素 99
  3. 在尾部再添加一组元素 [100, 101, 102]
  4. 在索引 2 的位置插入一个元素 66

最终应输出:

[10, 20, 66, 30, 99, 100, 101, 102]

三、删:4 种删除方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
lst = ['a', 'b', 'c', 'd', 'e']

# 1. 按值删除,只删第一次出现的
lst.remove('c')
print(lst)                # ['a', 'b', 'd', 'e']

# 2. 按索引弹出,并返回被弹元素
x = lst.pop(1)            # 索引 1
print(x, lst)             # 'b'  ['a', 'd', 'e']

# 3. 默认 pop() 弹末尾
last = lst.pop()
print(last, lst)          # 'e'  ['a', 'd']

# 4. 清空整个列表
lst.clear()
print(lst)                # []

【课堂小练习】

目标:考察列表按值删除、按索引pop、默认pop及clear四种常见删除/清空操作的区分与使用。

任务:

  1. 定义一个列表,lst = [‘red’, ‘green’, ‘blue’, ‘green’, ‘yellow’];
  2. 按值删除,仅删第一个’green’ ;
  3. 用pop(1)取出并打印索引1的元素及剩余列表;
  4. 无参pop()删掉末尾元素,打印该元素及剩余列表;
  5. 一键清空整个列表。

要求:每一步完成之后,都需要输出列表的值。

四、改 & 排序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
lst = [3, 1, 4, 1, 5]

# 1. 索引改值
lst[0] = 99
print(lst)                # [99, 1, 4, 1, 5]

# 2. 原地升序
lst.sort()
print(lst)                # [1, 5, 10, 20, 30, 99]

# 3. 原地降序
lst.sort(reverse=True)
print(lst)                # [99, 30, 20, 10, 5, 1]

# 4. 倒序(不管大小)
old = [3, 1, 4]
old.reverse()
print(old)                # [4, 1, 3]

五、查:索引、计数、是否存在

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
lst = ['p', 'y', 't', 'h', 'o', 'n']

# 20. 索引 → 元素
print(lst[0])               # 'p'
print(lst[-1])              # 'n'   倒数第一个

# 21. 元素 → 索引(找不到抛异常)
print(lst.index('t'))       # 2
# print(lst.index('x'))     # ValueError

# 22. 计数
print(lst.count('y'))       # 1

# 23. 是否存在
print('o' in lst)           # True

【课堂小练习】

目标:考察列表排序、最值获取、成员存在性判断与元素计数等基础操作。

任务:

  1. 定义一个列表, lst = [8, 3, 8, 5, 8, 2, 9, 3]
  2. 原地降序排序;
  3. 输出最大值;
  4. 判断数字 8 是否存在;
  5. 统计数字 8 出现的次数。

要求:每一步完成之后,都需要输出列表的值。

六、综合案例

【综合案例】“班级成绩管理小系统”

你手里有一份某次测验的原始成绩单,请利用列表的各种增删改查、排序、统计操作,一次性完成以下5个子任务(每步必须输出对应结果):

  1. 初始化与录入

    从空列表开始,依次追加5名同学的成绩:78, 85, 92, 85, 66

  2. 补录与修正

    ① 发现漏录一名同学,成绩为88,请将其插入到索引2的位置;

    ② 紧接着把92分同学的成绩改为95

  3. 去重与排序

    ① 仅删除第一次出现的85

    ② 将列表原地按升序排列并输出。

  4. 统计查询

    ① 输出当前最高分;

    ② 统计85分在新列表中出现的次数;

    ③ 判断90分是否存在于列表中。

  5. 清空备份

    把处理完的最终列表一次性清空,并输出“列表已清空,长度:X”。

3.3 字典(dict)

字典是 Python 的“查表神器”:把独一无二的“键”当成门牌号,秒查到对应的“值”,让数据有名有姓、一一对应,随时增删改查。

一、创建与查看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 1. 空字典 & 字面量
d1 = {}
d2 = {'name': 'Alice', 'age': 23}

# 2. dict() 构造器
d3 = dict(name='Bob', age=24)                 # 关键字形式
d4 = dict([('name', 'Cathy'), ('age', 25)])   # 二元组列表

# 3. 长度
print(len(d2))                                # 2

二、增 & 改:键存在就改,不存在就增

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
d = {'name': 'Alice', 'age': 23}

# 4. 直接赋值
d['gender'] = 'female'      # 新增
d['age'] = 24               # 修改
print(d)                    # {'name': 'Alice', 'age': 24, 'gender': 'female'}

# 5. setdefault:没有才新增,并返回最终值
old = d.setdefault('age', 30)      # 已存在,返回 24
new = d.setdefault('city', 'NY')   # 不存在,新增并返回 'NY'
print(d)                             # {'name': 'Alice', 'age': 24, 'gender': 'female', 'city': 'NY'}

# 6. 批量更新(字典合并)
d.update({'city': 'LA', 'email': 'a@.com'})  # 同键覆盖,新键添加
print(d)                                     # city 被改成 LA

【课堂小练习 · 字典“增改”案例】

  1. 已有字典 book = {'isbn': '978-7-111', 'title': 'Python基础'},用直接赋值方式新增价格 price 68 元,并把 title 改为 'Python核心编程',打印字典。

  2. 对同一字典使用 setdefault

    ① 若 price 已存在则返回其值,否则设为 88;

    ② 若 author 不存在则新增 '张三' 并返回该值;

    依次打印两个操作的返回值及字典。

  3. 对同一字典使用 update:一次性合并 {'price': 78, 'publisher': '机械工业'},其中 price 若已存在则覆盖,打印最终字典。

三、查:3 种取法 + 遍历全家桶

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
d = {'name': 'Alice', 'age': 23, 'scores': {'语文': 92, '数学': 98}}

# 7. 方括号取(找不到抛 KeyError)
print(d['name'])  # Alice
# print(d['gender'])  # KeyError: 'gender'

# 8. get 更安全地取,不会报错(可给默认值)
print(d.get('gender'))  # None
print(d.get('gender', 'unknown'))  # unknown
#
# 两次方括号取字典的值
print(d['scores'])  # 先取出成绩的字典内容
print(d['scores']['语文'])  # 再取出语文成绩
# # 9. 多级嵌套安全取
print(d.get('scores').get('语文'))      # 92
print(d.get('scores', {}).get('语文'))      # 92
#
# # 10. 遍历键
d = {'name': 'Alice', 'age': 23, 'scores': {'语文': 92, '数学': 98}}
for k in d:
    print(k, end=' ')       # name age scores
print()
# 和上面的效果一样
for k in d.keys():
    print(k, end=' ')       # name age scores
print()
#
# # 11. 同时遍历键值
# for k, v in d:  # ValueError: too many values to unpack (expected 2)
#     print(k, v)

for k, v in d.items():
    print(k, v)
# name Alice
# age 23
# scores {'语文': 92, '数学': 98}

# # 12. 只遍历值
for v in d.values():
    print(v, end=' ')       # Alice 23 {'语文': 92, '数学': 98}

【课堂小练习 · 字典“查询与遍历”案例】

  1. 已有字典 product = {'id': 'P1001', 'spec': {'颜色': '蓝色', '尺寸': 'L'}},用方括号取出 id 并打印;用 get 取出 price 并打印,若不存在则返回 -1

  2. 用多级 get 安全方式取出 spec颜色 的值并打印;再尝试取出 重量 并打印,若不存在则返回 '无数据'

  3. 分别用三种方式遍历 product

    ① 只遍历所有键并依次打印;

    ② 同时遍历键和值,每行打印 键:值; ③ 只遍历所有值并依次打印。

四、删:pop / clear

1
2
3
4
5
6
7
8
9
d = {'a': 1, 'b': 2, 'c': 3}

# 13. 按键删除并返回值
x = d.pop('b')
print(x, d)                 # 2 {'a': 1, 'c': 3}

# 14. 一键不留
d.clear()
print(d)                    # {}

五、综合案例

【综合案例 · 一份成绩单的“成长轨迹”】


初始空白档案

1
2
3
4
5
6
7
8
report = {
    "id": 2023001,
    "name": "Alice",
    "age": 18,
    "scores": {"语文": 92, "数学": 98, "英语": 88},
    "passed": True,
    "hobbies": ["reading", "swimming", "coding"]
}

任务1 补齐个人信息

① 新增性别 gender = 'F'

② 年龄 +1 → age = 19

③ 英语成绩提至 英语 = 90

➜ 打印字典(第一次“成长”)


任务2 安全补录

setdefaultage(已存在,返回 19 并打印)

setdefault 补录 hometown = 'Hangzhou'(新增并打印)

➜ 打印字典(家乡落户)


任务3 期末总评更新

批量 update 合并 {'passed': False, 'rank': 5}(原 passed 被覆盖)

➜ 打印字典(喜提未通过 & 年级排名)


任务4 快速查询

① 方括号取 id

getphone,缺失返回 'unknown'

③ 多级 getscores 内数学成绩,缺失返回 0

➜ 三个结果空格分隔一行打印


任务5 遍历全家福

① 遍历所有键

② 遍历键值对,格式 key:value

③ 遍历所有值

➜ 各用一行打印,元素间空格分隔


任务6 毕业清档

pop 删除并返回 rank

clear 一键清空整个字典

➜ 先打印 pop 返回值,再打印清空后字典(两行)

小白口诀

字典是“带名字的抽屉”,找东西用钥匙(键),钥匙不存在就 get 给默认,避免报错。

3.4 元组

一句话先记住:元组就是“不能改的列表”,一旦创建,长度、元素都锁死;也正因为“只读”,它才快、才安全,才能当字典/集合的钥匙。


一、创建 & 基本查看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 1. 小括号可省,逗号才是灵魂
t1 = (1, 2, 3)
t2 = 1, 2, 3          # 与上一行等价
single = (42,)        # 单元素必须加逗号,否则变成普通数字

# 2. 空元组
empty = ()

# 3. 长度 & 类型
print(len(t1))        # 3
print(type(t1))       # <class 'tuple'>

二、只读操作(能看,不能改)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
t = ('p', 'y', 't', 'h', 'o', 'n')

# 4. 索引 & 切片(和列表一模一样)
print(t[0])           # 'p'
print(t[-1])          # 'n'
print(t[1:4])         # ('y', 't', 'h')

# 5. 查找
print(t.index('t'))   # 2     第一次出现的位置
print(t.count('t'))   # 1     总共出现次数

# 6. 遍历
for ch in t:
    print(ch, end=' ')  # p y t h o n

三、不可改特性演示(会报错)

1
2
3
t = (1, 2, 3)
# t[0] = 10       # TypeError: 'tuple' object does not support item assignment
# t.append(4)     # AttributeError: 没有 append 方法

四、为啥要用元组?3 个场景

  1. 字典键 / 集合元素 列表不能当键,元组可以: pos = {(120.5, 30.2): "北京"}

  2. 函数多返回值 return x, y 实际返回的是一个元组。

  3. 并行赋值 for x, y in points: 拆包遍历,代码更短更快。


3.5 集合

集合是 Python 的“排重+速算”利器:一键去重、毫秒级判断元素是否存在,还能把交集、并集、差集等集合运算变成一行代码,专治重复与关系问题。

一、创建与查看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 1. 空集合 & 字面量
# {}
s1 = set()                 # 必须用 set(),{} 是空字典
d2 = {'name': 'Alice', 'age': 23}
s2 = {1, 2, 3}             # 字面量
lst = [1, 2, 2, 3]
s3 = set(lst)              # 列表去重
print(s3)                  # {1, 2, 3}

# 2. 不可变集合(可当作字典键)
fs = frozenset([4, 5, 6])
print(fs)                  # frozenset({4, 5, 6})

# 3. 长度
print(len(s2))             # 3

二、增:添加元素

1
2
3
4
5
6
7
8
9
s = {1, 2}

# 4. 加一个
s.add(3)
print(s)                   # {1, 2, 3}

# 5. 加一堆(可迭代)
s.update([4, 5], (6, 7))
print(s)                   # {1, 2, 3, 4, 5, 6, 7}

三、删:4 种常用删除

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
s = {10, 20, 30, 40}

# 6. 删除指定元素(不存在抛 KeyError)
s.remove(20)
print(s)                   # {10, 30, 40}

# 7. 安全删除(不存在不报错)
s.discard(999)             # 无异常

# 8. 随机弹出一个并返回(集合无顺序)
x = s.pop()
print(x, s)                # 10 {30, 40}  (结果可能不同)

# 9. 一键清空
s.clear()
print(s)                   # set()

四、集合运算:交并差

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
A = {1, 2, 3, 4}
B = {3, 4, 5, 6}

# 10. 交集 &
print(A & B)               # {3, 4}
print(A.intersection(B))   # 同上

# 11. 并集 |
print(A | B)               # {1, 2, 3, 4, 5, 6}
print(A.union(B))          # 同上

# 12. 差集 -
print(A - B)               # {1, 2}
print(A.difference(B))     # 同上

五、综合案例

【综合案例题:小明的图书标签整理】

小明是一位图书管理员,他手头有两份本周新到馆的图书标签列表,分别来自两个不同的编目系统。每个标签用字符串表示,列表中可能存在重复标签。

列表 A(第一份): ["Python", "算法", "Python", "数据结构", "算法", "数据库"]

列表 B(第二份): ["算法", "机器学习", "数据库", "深度学习", "算法"]

现在他需要你帮忙完成以下任务:

  • 使用集合一次性去除每份列表中的重复标签;
  • 找出两份列表共同拥有的标签(交集);
  • 统计只在第一份列表出现的标签(差集);
  • 把所有去重后的标签合并成一份完整无重复的总标签库(并集);
  • 最后,从总标签库中随机弹出一个标签作为本周推荐标签并打印。

要求:每一步完成之后,都需要输出结果的值。

4 程序控制流——让代码会“拐弯”

4.1 条件语句

一、单分支

单分支:只有一个“如果”,语法:

1
2
3
if 条件:
    条件为真才执行的代码块必须缩进 4 个空格
后续代码继续从这里开始不再受 if 控制

示例:

1
2
3
4
score = 75
if score >= 60:               # 只有一个判断入口
    print("恭喜你,及格了!")   # 条件成立才执行
print("程序结束")             # 不管条件成不成立都会执行

二、双分支

双分支:非此即彼,语法:

1
2
3
4
5
if 条件:
    条件为真执行的代码块
else:
    条件为假执行的代码块
两条分支必走且仅走一条

示例:

1
2
3
4
5
6
score = 55
if score >= 60:
    print("及格")      # 条件为真走这里
else:
    print("不及格")    # 条件为假走这里
print("成绩判断完毕")  # 后续代码

三、多分支

多分支:依次判断多个条件,语法:

1
2
3
4
5
6
7
8
9
if 条件1:
    条件1为真执行的代码块
elif 条件2:
    条件1为假且条件2为真执行的代码块
elif 条件3:
    前两个条件为假且条件3为真执行的代码块
else:
    前面所有条件都为假才执行的代码块
整个结构最多只会执行其中一个分支

注:elifelse if的简写,表示“否则如果”。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
score = 83
if score >= 90:
    print("优秀")
elif score >= 80:      # 上一个条件已经过滤掉 ≥90
    print("良好")
elif score >= 70:
    print("中等")
elif score >= 60:
    print("及格")
else:
    print("不及格")
print("等级评定完成")

小白注意:判断可以连写:200 <= code < 300 完全合法。

四、综合练习

某市出租车按行驶里程 distance(公里,浮点数)计费,规则如下:

  1. 起步价 10 元,含 2 公里;
  2. 2–20 公里(含):每公里 1.6 元;
  3. 20 公里以上:每公里 2.4 元。

请计算并输出以下三种里程的车费,结果保留到分(2 位小数):

① 1.8 km ② 18.6 km ③ 26.4 km

4.2 循环语句

循环语句的核心作用是:让计算机重复执行某段代码,直到满足特定条件为止。

Python 中有两种主流循环whilefor)以及配套关键字break / continue / else)。


1.while 循环

Python 的 while 循环用于重复执行一段代码块,只要条件为真。它是“条件控制型”循环,不像 for 是“计数控制型”。

基本语法结构

1
2
while 条件表达式:
    循环体
  • 条件表达式 返回布尔值(TrueFalse)。
  • 每次循环开始前都会重新评估条件。
  • 如果条件为 True,执行循环体;否则退出循环。

示例1:打印 1 到 5

1
2
3
4
i = 1
while i <= 5:
    print(i)
    i += 1

示例2:while循环遍历列表

1
2
3
4
5
6
7
8
data = [4, -3, -9, 12, 5]
index = 0
# len(data) = 5
# 0 1 2 3 4
while index < len(data):
    num = data[index]
    print(num, end=' ')
    index += 1

控制语句:breakcontinueelse

  • break:提前退出整个循环
  • continue:跳过本次迭代,继续下一轮。
  • else:循环正常走完才执行(被 break 就不执行),常用于“查找失败”场景。

示例:break

1
2
3
4
5
6
i = 1              # 初始化计数器
while True:        # 无限循环(需内部用 break 退出)
    print(i)       # 打印当前 i
    if i == 3:     # 当 i 等于 3 时
        break      # 立即跳出整个 while 循环
    i += 1         # 自增,准备下一轮

示例:continue

1
2
3
4
5
6
i = 0                 # 初始化计数器
while i < 5:          # 当 i 小于 5 时继续循环
    i += 1              # 先自增(本次循环 i 从 1 开始)
    if i == 3:          # 如果 i 为 3
        continue        # 跳过本轮剩余语句(不执行下面的 print)
    print(i)            # 输出当前 i 值(3 被跳过)

示例:else

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 在列表里查找第一个 > 100 的数
nums = [23, 45, 78, 99, 88]     # 注意:没有 >100 的数

for n in nums:
    if n > 100:
        print('找到大于 100 的数:', n)
        break                   # 找到就提前跳出
else:
    # 如果 break 没触发,说明全程没找到
    print('扫描结束,列表里没有大于 100 的数')

死循环(慎用)

1
2
while True:
    print("无限循环")

⚠️ 注意:死循环必须配合 break 或外部中断(如 Ctrl+C)退出。


2.for 循环

Python 的 for 循环本质上是一种 “遍历(迭代)循环”,它不会自己去“计数”,而是 逐个取“可迭代对象”里的元素,直到取完为止。

基础语法骨架

可迭代对象:list、tuple、str、bytes、range、dict、set、生成器、自定义迭代器……

  • 目标变量:每次循环从可迭代对象里取出的当前元素,名字随意起。
  • else 块:仅当循环没有被 break 中断时才会运行。

最常用的 6 种遍历模式

场景 代码片段 说明
① 遍历 list / tuple for item in ['a','b','c']: 元素直接拿
② 遍历字符串 for ch in 'hello': 逐个字符
③ 遍历字典键 for k in d:for k in d.keys(): 默认就是键
④ 遍历字典键值对 for k, v in d.items(): 拆包同时拿键值
⑤ 带索引遍历 for idx, item in enumerate(lst): 从 0 开始计数
⑥ 指定区间步长 for i in range(start, stop, step): 半开区间 [start, stop)

range函数:

1
2
3
4
5
6
7
8
9
list(range(5))        # [0, 1, 2, 3, 4]
list(range(0, 5))        # [0, 1, 2, 3, 4]

list(range(2, 8))     # [2, 3, 4, 5, 6, 7]
list(range(2, 8, 1))     # [2, 3, 4, 5, 6, 7]

print(list(range(1, 10, 2))) # [1, 3, 5, 7, 9]
print(list(range(5, 0, -1))) # [5, 4, 3, 2, 1]
print(list(range(5, 0, 1)))  # []  方向相反

示例1:遍历 list / tuple

1
2
3
4
colors = ['red', 'green', 'blue']
for c in colors:
    print(c, end=' ')
# 输出: red green blue 

示例2:遍历字符串(逐字符)

1
2
3
4
word = "Python"
for ch in word:
    print(ch, end='-')
# 输出: P-y-t-h-o-n-

示例3:遍历字典的键

1
2
3
4
scores = {'Tom': 90, 'Lucy': 95}
for name in scores:        # 等价于 scores.keys()
    print(name, end=' ')
# 输出: Tom Lucy 

示例4:遍历字典的键值对

1
2
3
4
scores = {'Tom': 90, 'Lucy': 95}
for name, score in scores.items():
    print(f'{name}:{score}', end=' | ')
# 输出: Tom:90 | Lucy:95 | 

示例5:带索引遍历(enumerate)

1
2
3
4
colors = ['red', 'green', 'blue']
for idx, color in enumerate(colors):
    print(f'{idx}{color}', end='  ')
# 输出: 0→red  1→green  2→blue  

示例6:指定区间与步长(range)

1
2
3
4
# 打印 1~10 内的奇数
for n in range(1, 11, 2):
    print(n, end=' ')
# 输出: 1 3 5 7 9 

3.循环控制语句

控制语句:breakcontinueelse

  • break:提前退出整个循环
  • continue:跳过本次迭代,继续下一轮。
  • else:循环正常走完才执行(被 break 就不执行),常用于“查找失败”场景。

一、break:立刻“跳出整个循环”,语法:

1
2
3
for ... in ...:
    ...
    break          # 遇到即退出 for/while 所在的最内层循环

执行流程图

1
循环体 → 遇到 break → 直接跳到循环块之后的第一条语句

两大典型模板

“找到即停”

1
2
3
4
5
6
7
# 在列表里找到第一个负数就打印并结束
nums = [3, 7, 0, -5, 9]
for v in nums:
    print(v,end=" ")
    if v < 0:
        print('第一个负数是', v)
        break        # 后面 9 不再扫描

while 死循环 + break 出口

1
2
3
4
5
6
7
import random
while True:                     # 看似“死循环”
    n = random.randint(1, 10)
    print('roll →', n)
    if n == 6:
        break                   # 掷出 6 点即退场
print('终于掷出 6,收工!')

易错点

  • break 只能跳出一层循环;嵌套多层需要在对应层写 break。
  • if 搭配时一定注意缩进,千万别把 break 写到 if 外。

二、continue:跳过“本轮剩余语句”,直接下一轮,语法:

1
2
3
for ... in ...:
    ...
    continue       # 立即结束本轮,进入“迭代器下一步”

执行流程图

1
循环体 → 遇到 continue → 本轮剩余语句不再执行 → 回到循环头取下一个元素

典型模板——“过滤式”处理

1
2
3
4
5
6
# 只处理正数,负数和 0 直接无视
data = [4, -3, 0, 7, -6, 8]
for x in data:
    if x <= 0:
        continue      # 负数/0 直接跳过
    print('正数:', x)

易错点

while 循环里写 continue 时,务必确保循环变量仍被更新,否则容易变真·死循环:

1
2
3
4
5
6
i = 0
while i < 5:
    if i == 3:
        continue   # 忘写 i += 1 → 永远卡在 3
    print(i)
    i += 1

三、for / while … else:只有“没被 break”时才跑,语法:

1
2
3
4
5
6
7
for 变量 in 可迭代对象:
    ...
    if 某条件:
        break
else:
    # 可迭代对象全部取完、且从未 break,才会进来
    ...

执行流程图

1
2
循环正常结束(迭代器耗尽)→ 执行 else 块  
循环被 break 提前中断 → 跳过 else 块

两大经典场景

“查找失败提示”(最常用)

1
2
3
4
5
6
for n in [2, 4, 6]:
    if n == 5:
        print('找到了')
        break
else:               # 没被 break,说明没找到
    print('列表里没有 5')

“重试超限”

1
2
3
4
5
6
7
for i in range(3):
    pwd = input('密码:')
    if pwd == '123':
        print('正确')
        break
else:               # 3 次都没 break
    print('3 次都输错,锁定')

易错点

elsefor/while 对齐,千万莫缩进到 if 层,否则逻辑全变。


综合示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 需求:在 1~10 中找能被 7 整除的数
#  1. 找到 → 打印并 break
#  2. 偶数 → 跳过(continue)
#  3. 全扫描完都没找到 → else 提示
for n in range(1, 11):
    if n % 2 == 0:
        continue          # 偶数不看
    if n % 7 == 0:
        print('找到奇数且能被 7 整除的数:', n)
        break
else:
    print('扫描结束,没有符合要求的数')
1
2
3
4
5
6
7
8
9
# ctrl + D
print(10 % 2)  # 0
print(10 % 3)  # 1
print(10 % 4)  # 2
print(10 % 5)  # 0
print(9 % 2)  # 1
print(9 % 3)  # 0
print(9 % 4)  # 1
print(9 % 5)  # 4

运行结果(仅两种可能):

1
找到奇数且能被 7 整除的数: 7

或(若把范围改成 1~5)

1
扫描结束,没有符合要求的数

4.综合练习

【题目 1 】

已知列表 data = [4, -3, -9, 12, 5, 6, 3, 0],用 while 循环遍历该列表(遇到 0 即停):

① 若元素值负数,则忽略;

② 当出现两次数字能被 3 整除时,立刻输出它们的和并结束程序;

③ 若遍历到 0 时仍未出现上述连续两数,输出“条件未达成”。

要求:必须使用 whilecontinuebreakelse

【题目 2】

驿站收到一串包裹重量(克)列表:

1
weights = [1200, -1, 580, 3200, 2100, -2, 450]
  • 负数表示扫描失败,直接跳过;
  • 一旦遇到 > 2000 克 的大件包裹,立即输出其重量并终止分拣;
  • 若全部扫描完都没有大件,输出 "所有包裹均为小件,自动分拣完成"

要求: 仅用 一次 for...else 循环实现,必须用 continuebreak

5 函数与模块——把代码“打包”复用

5.1 自定义函数

把“会重复用到的几行代码”取个名字,以后想用时直接喊这个名字,就能一次性跑完——这就是自定义函数。

在 Python 中,自定义函数使用 def 关键字来定义,基本语法如下:

一、基本语法结构

1
2
3
4
def 函数名(参数1, 参数2, ...):
    """文档字符串(可选,用于说明函数功能)"""
    函数体
    return 返回值  # 可选

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def add(a, b):
    """返回两个数的和"""
    print("a=",a)
    print("b=",b)
    c = a + b
    return c

# 调用函数
result = add(3, 5)
print(result)  # 输出 8
result = add(38, 55)
print(result)  # 输出 93
result = add(342, 866)
print(result)  # 输出 1208

关键点说明

元素 说明
def 定义函数的关键字
函数名 应符合标识符命名规则(小写+下划线推荐)
参数 可选,支持默认值、可变参数等
return 返回值,若无则返回 None

小白步骤

  1. def 起头 → 写函数名 → 括号里写参数。
  2. 冒号结尾 → 函数体必须缩进。
  3. 想返回结果就 return,不写默认返回 None

二、函数参数的类别

在 Python 中,自定义函数的参数可以分为以下几种主要类别:

1.位置参数

  • 按照参数位置依次传递,调用时必须提供。
  • 是最常见的参数类型。
1
2
3
4
def add(a, b):
    return a + b

add(1, 2)  # 1 对应 a,2 对应 b

2.默认参数

  • 默认参数必须放在非默认参数之后。
  • 参数有默认值,调用时可以不传。
1
2
3
4
5
6
7
def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

greet("Alice")  # 输出:Hello, Alice!
greet("Taylor")  # 输出:Hello, Taylor!
greet("张三", "早上好")  # 早上好, 张三!
greet("李四", "你好")  # 你好, 李四!

3.关键字参数

  • 调用函数时,使用 参数名=值 的形式,顺序不重要。
  • 提高代码可读性。
1
2
3
4
5
6
7
8
9
def divide(a, b):
    return a / b

# c = divide(a1=100, b1=10)  # 指定参数名时,参数名一定要正确
# print(c)
c = divide(a=100, b=10)  # 顺序无关
print(c)
c = divide(b=4, a=10)  # 顺序无关
print(c)

三、综合练习

【题目 1:学生信息录入】

要求

  1. 自定义函数 add_student,参数依次为 nameagegendercity(默认值为 "北京")。
  2. 调用函数时,必须指定参数名传入 gender,其余参数可按位置或指定参数名传入。
  3. 函数返回格式化的字符串:"姓名:{name},年龄:{age},性别:{gender},城市:{city}"

示例

1
2
3
# 调用示例
result = add_student("张三", 18, gender="男")
print(result)  # 输出:姓名:张三,年龄:18,性别:男,城市:北京

【题目 2:计算订单总价】

要求

  1. 自定义函数 calculate_total,参数为 pricequantity(默认值为 1)、discount(默认值为1,表示无折扣,折扣值为 0~1 的小数)。
  2. 调用函数时,必须按指定参数名传入 discount,其余参数可按位置或指定参数名传入。
  3. 函数返回折后总价(保留两位小数)。

示例

1
2
3
# 调用示例
total = calculate_total(100, 3, discount=0.8)
print(total)  # 输出:240.00(原价300,打8折)

5.2 模块导入

1
2
3
4
5
6
7
import os, sys, json # 标准库
import requests # 第三方库

# 调用
print(os.getcwd())# 当前文件夹路径
resp = requests.get("https://httpbin.org/get", timeout=5)
print(resp.status_code) # 200

终端中执行命令:pip install requests

import 顺序口诀

标准库 → 第三方库 → 自己写的库,中间空一行,方便阅读。


6 文件操作——把数据“倒”进硬盘

在 Python 中,写入文件的基本语法如下:

1. 使用 open()write() 方法

1
2
3
4
5
6
7
# 打开文件(如果文件不存在会自动创建)
file = open('example.txt', 'w', encoding='utf-8')
# 写入内容
file.write('Hello, world!\n')
# 关闭文件
file.close()
print("文件写入完成!")
  1. 打开(或创建)文件:使用 open('example.txt', 'w', encoding='utf-8')写入模式'w')打开一个名为 example.txt 的文件。

    • 如果文件已存在,会清空原内容
    • 如果文件不存在,会自动创建新文件。
    • encoding='utf-8' 指定使用 UTF-8 编码写入,确保支持中文等特殊字符。
  2. 写入内容file.write('Hello, world!\n') 将字符串 "Hello, world!\n" 写入文件。

    • \n 表示换行,写入后文件内容会另起一行。
  3. 关闭文件file.close() 手动关闭文件,释放系统资源。

    • 关闭后,对文件的操作结束,确保数据完全写入磁盘。

【总结】这段代码会创建(或清空)一个 UTF-8 编码的 example.txt 文件,写入一行 "Hello, world!" 并换行,最后关闭文件。

2. 使用 with 语句(推荐方式)

1
2
with open('example.txt', 'w', encoding='utf-8') as file:
    file.write('Hello, world!\n')
  1. with … as file:
    • 自动生成一个文件对象 file离开 with 块时自动调用 file.close(),即使中途出错也能保证文件被正确关闭。
  2. 模式 'w'
    • 若文件已存在,原内容会被清空;不存在则新建。
  3. encoding='utf-8'
    • 明确采用 UTF-8 编码,防止中文等非 ASCII 字符乱码。
  4. write('Hello, world!\n')
    • 把字符串写进文件,并在行尾加换行符 \n

【总结】这段代码用“with 语句”以 写入模式 打开(或创建)example.txt,把 "Hello, world!\n" 写进去,写完自动关闭文件

3. 追加写入(不覆盖原内容)

1
2
3
4
5
6
with open('示例.txt', 'w', encoding='utf-8') as file:
    file.write('你好,世界!\n')
# 第二个参数 a  append 表示追加写入
with open('示例.txt', 'a', encoding='utf-8') as file:
    file.write('追加文本内容成功!\n')
print("文件写入成功!")

要求:在评论区提交生成的 示例.txt 文件内容的截图。

  • 'a':以追加模式(append)打开文件。如果文件不存在,会创建新文件;如果存在,写入的内容会添加到文件末尾,不会覆盖原有内容。

4.从文件读取数据

在 Python 中,读取文件内容最常用的方式是使用内置的 open() 函数,结合 with 语句来确保文件正确关闭。以下是几种常见的读取方式:


1.读取整个文件内容

1
2
3
with open('example.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    print(content)
  • 'r' 表示以只读文本模式打开文件。

2.逐行读取

【方式1】

1
2
3
with open('example.txt', 'r', encoding='utf-8') as f:
    for line in f:
        print(line.strip())
  • for line in f:逐行遍历文件对象 f,每次循环 line 是一个字符串,包含当前行的内容(包括行末的换行符 \n)。

【方式2】

1
2
3
4
5
with open('example.txt', 'r', encoding='utf-8') as f:
    line = f.readline()
    while line:  # 等价于 line != ''
        print(line, end='')  # 避免重复换行
        line = f.readline()
  • line = f.readline():读取文件的第一行(含行尾 \n),赋给变量 line。若文件为空,则 line''
  • while line::只要读到的字符串非空,就继续循环;到文件末尾时 readline() 返回 '',循环结束。

3.读取所有行到列表

1
2
3
with open('example.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()
    print(lines)  # 每行作为列表中的一个元素

5.课堂小练习

练习1

【课堂小练习】 文件操作练习1:将列表中的数字逐行写入文本文件

题目描述

给定一个 Python 列表 numbers,其中包含 10 个浮点数或整数元素,请编写一段程序,将列表中的每个数字按顺序逐行写入一个名为 num.txt 的文本文件中。要求使用 utf-8 编码,并在文件写入完成后,在控制台输出提示信息:“num.txt 已生成,共 10 个数字。”

要求

  1. 使用 with open(...) 语句打开文件,确保文件正确关闭。
  2. 每个数字占一行,数字与数字之间不能有空行。
  3. 评论时截图需要截取 num.txt 文件的内容。

示例

假设列表为:

1
numbers = [3.5, 7, 11.2, 0, -4, 9, 2.8, 100, 6.6, 42]

程序运行后,生成的 num.txt 文件内容应为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
3.5
7
11.2
0
-4
9
2.8
100
6.6
42

控制台输出:

1
num.txt 已生成,共 10 个数字。

提示

  • 使用 for 循环遍历列表。
  • 使用字符串格式化(如 f-string)将数字转为字符串并写入文件。
  • 每行末尾需添加换行符 \n

练习2

用 Python 的 with 语句,先清空(或新建)poem.txt,依次写入两行诗句并追加两行,再完整读出打印,最后逐行统计并输出行数,确保文件最终含四句诗且被正确关闭。

任务要求

  1. poem.txt 已存在,请先清空它;若不存在则创建。

  2. 向文件写入下面两行诗句(不包括行号,每行后要有换行):

    1
    2
    
    春眠不觉晓,
    处处闻啼鸟。
  3. 追加第三、四行诗句:

    1
    2
    
    夜来风雨声,
    花落知多少。
  4. 读取整个文件内容并赋值给变量 full_text,然后打印 full_text

  5. 重新以逐行方式读取文件,统计文件的总行数,并将结果打印为:

    1
    
    文件共有 X 行。
  6. 整个过程中必须使用 with 语句,确保文件被正确关闭。

请用一段完整的 Python 代码实现以上 6 个步骤,并确保最后文件 poem.txt 的内容为:

1
2
3
4
春眠不觉晓,
处处闻啼鸟。
夜来风雨声,
花落知多少。

6. 写入 CSV 文件

csv文件说明

Comma-Separated Values,“逗号分隔值” 的纯文本表格格式,一行就是一条记录,字段之间用逗号(或其他符号)隔开

没有复杂格式、没有宏,任何文本编辑器都能打开,也被 Excel、Pandas、数据库等直接识别。

核心规则(标准 RFC 4180)

  1. 每行一条记录,行尾 \r\n\n
  2. 字段默认用逗号 , 分隔;也可指定分号、制表符等。
  3. 字段内容若出现 逗号、换行、双引号,整个字段必须用 双引号 包裹。
  4. 字段内的双引号要写成 两个连续双引号 ""
  5. 文件通常可选第一行做 表头(列名)。

示例

1
2
3
4
Name,Age,City
Alice,25,"New York"
Bob,30,"Boston"
"Charlie ""Chuck""",22,"San Francisco"

优点

  • 纯文本,跨平台、跨语言、体积小。
  • 读写简单,几乎任何软件/编程语言都有现成解析器。

缺点

  • 只存数据,不保存类型、公式、颜色等富信息。
  • 如果字段里逗号、引号多,人工阅读较乱。

一句话:CSV 就是“最小化电子表格”,用来朴素、高效地搬数据。

写入csv文件

1
2
3
4
5
6
7
8
import csv

rows = [['Name', 'Age'], ['Alice', 25], ['Bob', 30]]

with open('data.csv', 'w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerows(rows)
print("csv文件写入完成!")
  1. newline='' 阻止 Python 在 Windows 下把 \n 写成 \r\n,避免产生空行。

  2. csv.writer(file) 创建一个按 CSV 规则处理逗号、引号、转义的写入器。

  3. writer.writerows(rows) 一次写入多行,结果文件内容:

    1
    2
    3
    
    Name,Age
    Alice,25
    Bob,30

【总结】把二维列表 rows 写成标准 CSV 文件 data.csv自动处理空行、UTF-8 编码,写完自动关闭文件

7. 写入 Excel 文件

(使用 openpyxl

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws['A1'] = 'Name'
ws['B1'] = 'Age'
ws.append(['Alice', 25])
ws.append(['Bob', 30])

wb.save('data.xlsx')
  1. from openpyxl import Workbook 导入 openpyxl 的 Workbook 类(内存中的空 Excel 文件)。

  2. wb = Workbook() 创建空白工作簿,自动带一张名为 “Sheet” 的工作表。

  3. ws = wb.active

    拿到当前活动工作表对象 ws。

  4. ws['A1'] = 'Name' ws['B1'] = 'Age' 给单元格直接赋值,写入表头。

  5. ws.append(['Alice', 25]) ws.append(['Bob', 30]) 按行追加列表:自动依次填到 A2/B2、A3/B3。

  6. wb.save('data.xlsx') 把整个工作簿写入磁盘,生成真正的 .xlsx 文件。

【总结】用 openpyxl 新建一个 Excel 工作簿,把表头 “Name / Age” 写在 A1/B1,再追加两行数据,最后保存为 data.xlsx

8. JSON 文件

JSON说明

JSON(JavaScript Object Notation)是一种轻量级、文本格式的数据交换标准,易于人阅读和编写,也易于机器解析和生成。它基于 JavaScript 的子集,但独立于语言,几乎所有现代编程语言都内置支持。


核心特性
  1. 纯文本:完全由 Unicode 字符(如 UTF-8)组成,无二进制内容。
  2. 键值对结构:数据以 键:值 的形式存储,键必须是双引号包裹的字符串
  3. 层次化:支持嵌套的对象(Object)和数组(Array),可表示复杂数据结构。
  4. 无冗余:无注释(///* */ 不允许),无尾随逗号(如 [1, 2,] 会报错)。

数据类型
类型 示例 规则
对象 {"name": "Alice"} 无序的键值对集合,键必须是字符串,值可以是任意合法类型。
数组 [1, "2", true] 有序的值列表,元素类型可混合。
字符串 "hello\n世界" 必须用双引号,支持转义(如 \"\\\u4e2d 表示 Unicode 字符)。
数字 42, -3.14, 1e10 仅支持十进制,无 NaNInfinity(需用 null 或字符串替代)。
布尔值 true, false 小写,无其他写法(如 True 报错)。
空值 null 表示“无值”,区别于 0""undefined(后者在 JSON 中非法)。

示例对比

合法 JSON

1
2
3
4
5
6
7
{
  "users": [
    {"id": 1, "name": "张三", "vip": true, "balance": null},
    {"id": 2, "name": "Bob", "vip": false, "balance": 123.45}
  ],
  "total": 2
}

非法 JSON

1
2
3
4
5
{
  "name": 'John',      // 错误:单引号
  "age": undefined,    // 错误:无 undefined 类型
  "list": [1, 2, 3,]  // 错误:尾随逗号
}

常见用途
  • API 通信:如 RESTful 接口的请求/响应体(如 {"code": 200, "data": {...}})。
  • 配置文件:如 package.json(Node.js)、tsconfig.json(TypeScript)。
  • 数据存储:NoSQL 数据库(如 MongoDB)以 JSON 格式存储文档。

JSON示例

示例1:用户配置(user-config.json)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    "user": "alice", 
    "theme": "dark", 
    "locale": "zh-CN", 
    "shortcuts": {
        "save": "Ctrl+S", 
        "search": "Ctrl+Shift+F"
    }, 
    "editor": {
        "fontSize": 14, 
        "tabSize": 2, 
        "wordWrap": true
    }
}

示例2:商品列表(products.json)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[
    {
        "id": 1001, 
        "name": "iPhone 15 Pro", 
        "price": 7999, 
        "currency": "CNY", 
        "inStock": true, 
        "tags": [
            "手机", 
            "苹果", 
            "5G"
        ]
    }, 
    {
        "id": 1002, 
        "name": "小米14", 
        "price": 3999, 
        "currency": "CNY", 
        "inStock": false, 
        "tags": [
            "手机", 
            "小米", 
            "徕卡"
        ]
    }
]

示例3:RESTful 接口返回(api-user-by-id.json)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
    "code": 200, 
    "msg": "success", 
    "data": {
        "id": 42, 
        "username": "bob", 
        "email": "bob@example.com", 
        "profile": {
            "avatar": "https://example.com/avatar/42.png", 
            "bio": "喜欢滑雪与摄影", 
            "followers": 1203
        }, 
        "createdAt": "2023-07-01T08:30:00Z"
    }
}

写入json文件

示例1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import json

# 1. 创建一个 Python 字典
data = {
    "姓名": "李雷",
    "年龄": 19,
    "是否学生": True,
    "技能": [
        "Python",
        "数据分析",
        "机器学习"
    ],
    "城市": "北京"
}

# 2. 将字典写入 JSON 文件
file_name = "student.json"
with open(file_name, "w", encoding="utf-8") as f:
    # json.dump(data, f)
    # json.dump(data, f, ensure_ascii=False)
    json.dump(data, f, ensure_ascii=False, indent=4)

print(f"字典已写入 {file_name} 文件")

# 3. 从 JSON 文件中读取字典
with open(file_name, "r", encoding="utf-8") as f:
    loaded_data = json.load(f)

print("从文件读取的字典:")
print(loaded_data)

【代码说明】

json.dump(data, f, ensure_ascii=False, indent=4):把内存中的变量 data(通常是 dict / list 等 Python 对象)序列化成 JSON 格式的字符串,并直接写入文件 f

  • ensure_ascii=False:允许写入非 ASCII 字符(如中文),否则会被转义成 \uXXXX
  • indent=4:让 JSON 多行缩进 4 个空格,美观易读。

loaded_data = json.load(f):把文件中的 JSON 文本反序列化成 Python 对象,赋值给变量 loaded_data。此时 loaded_data 的数据类型/结构与原来的 data 基本一致(字典、列表、嵌套结构等)。


7 异常处理——让程序“摔倒了”也能爬起来

在 Python 中,异常处理主要通过 try...except...else...finally 语句来实现。基本语法如下:


1.基本语法结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
try:
    # 可能引发异常的代码
    pass
except SomeException as e:
    # 异常处理代码
    pass
else:
    # 如果 try 块没有发生异常,则执行这里的代码
    pass
finally:
    # 无论是否发生异常都会执行的代码(可选)
    pass
  • pass是一个空操作语句——什么都不做,只是占位。保持语法完整,避免解释器报错。

  1. try 语句块(必写
1
2
3
try:
    # 可能引发异常的代码
    pass
  • 只要这里面的任何一条语句抛出了异常,解释器会立即中断 try 内剩余语句,去匹配后面的 except;
  • 如果 try 里没有异常,则跳过所有 except,去走 else(如果有)。

  1. except 语句块(0 个或多个
1
2
3
except SomeException as e:
    # 异常处理代码
    pass
  • 顺序匹配:从上到下第一个类型相符的 except 会被执行,其余忽略。
  • e 就是 被捕获的那个异常实例(对象),通过它你可以查看异常信息:print(e)str(e)

  1. else 语句块(0 个或 1 个必须在所有 except 之后、finally 之前
1
2
3
else:
    # 如果 try 块没有发生异常,则执行这里的代码
    pass
  • 仅当 try 块完全没有抛异常时才执行。

  1. finally 语句块(0 个或 1 个必须放在最末尾
1
2
3
finally:
    # 无论是否发生异常都会执行的代码(可选)
    pass
  • 0~1 个,固定放在最后;
  • 无论是否发生异常、无论是否已 return/break,都必定执行;
  • 常用于释放资源。

执行顺序一张图记住:

1
2
3
无异常:try → else → finally → 结束
有异常且匹配:try → 对应 except → finally → 结束
有异常无匹配:try → finally → 结束

2.基本示例

数组越界异常

1
2
3
4
5
6
7
# 数组越界捕获示例
lst = [10, 20, 30]  # 0 1 2

print(lst[0])
print(lst[1])
print(lst[2])
print(lst[3])  # IndexError: list index out of range

数组越界捕获示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
lst = [10, 20, 30]

try:
    value = lst[5]          # 越界索引
except IndexError as e:     # e 就是越界异常实例
    print("越界啦:", e)
else:
    print("取到的值:", value)
finally:
    print("收尾工作")

说明:

  • try:包裹可能出错的代码。
  • except:捕获并处理特定异常。
  • else:如果 try 中没有异常,则执行。
  • finally:无论是否发生异常,都会执行(常用于清理资源,如关闭文件、网络连接等)。

3.捕获所有异常

上面的IndexError只能捕获数组越界错误。可以使用下面的代码来捕获程序的所有异常。

1
2
3
4
try:
    risky_code()
except Exception as e:
    print("发生了异常:", e)

⚠️ 注意:捕获所有异常会掩盖程序中的错误,建议只捕获你能处理的异常。

兜底所有剩余异常(类型错误、键错误、系统错误……)。

一旦前面没有命中任何“具体异常”,就会落到这一层,防止程序因为“意料之外的错误”而崩溃。


4.手动抛出异常

在 Python 中,raise 是用于手动触发异常的关键字。它的作用是让程序在特定条件下主动抛出异常,从而中断当前流程,进入异常处理机制。


基本语法

1
raise SomeException("可选的错误信息")

示例1

获取年龄,若为负数则主动抛出 ValueError 并捕获处理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
try:
    age = int(input("请输入年龄:"))
    if age < 0:
        # 使用 raise 语句手动抛出 ValueError 异常,并附带错误信息
        raise ValueError("年龄不能是负数!")
except ValueError as e:
    # 捕获并处理抛出的 ValueError 异常
    print(f"捕获到 ValueError 异常:{e}")
else:
    print(f"年龄:{age}")
  1. 提示用户输入年龄,并尝试将输入转换为整数。
  2. 检查年龄是否为负数
    • 如果是负数,手动抛出 ValueError 异常,并附带错误信息“年龄不能是负数!”。
  3. 捕获并处理 ValueError 异常
    • 如果输入不是有效的整数(例如输入了字母),Python 会自动抛出 ValueError,也会被 except 捕获。
    • 如果年龄为负数,手动抛出的 ValueError 也会被捕获。
  4. 如果没有异常发生,则打印用户输入的年龄。

总结:这段代码用于安全地获取用户输入的年龄,并对非整数输入负数年龄进行异常处理,避免程序崩溃。

示例2

读取用户输入的密码,若长度不足 6 位则主动抛出并捕获 ValueError,否则提示设置成功。

1
2
3
4
5
6
7
8
try:
    pwd = input("设置新密码(至少6位):")
    if len(pwd) < 6:
        raise ValueError("密码长度不足6位!")
except ValueError as e:
    print(f"捕获到 ValueError 异常:{e}")
else:
    print("密码设置成功。")

4.异常捕获综合示例

示例1

读取整数并计算 10 除以该数,捕获非整数或除零异常

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
try:
    x = int(input("请输入整数:"))
    y = 10 / x
except ValueError as e:
    print("输入不是整数:", e)
except ZeroDivisionError as e:
    print("除以 0 啦:", e)
except Exception as e:
    print("未捕获的异常:", type(e).__name__, e)
else:
    print("结果 =", y)
finally:
    print("无论对错,都会执行 finally")

代码功能:

代码段 功能说明
try: 开始监视下面两行语句,任何一步抛异常都会被捕获。
x = int(input("请输入整数:")) 把用户输入转成 int;如果输入不是合法整数,会抛 ValueError
y = 10 / x 用 10 除以用户输入;如果用户输入 0,会抛 ZeroDivisionError
except ValueError as e: 专门接住“输入不是整数”的情况,打印友好提示。
except ZeroDivisionError as e: 专门接住“除以 0”的情况,打印友好提示。
except Exception as e: 兜底:如果前面两个具体异常都没命中,任何其他异常(理论上已没有,但写库/写服务时常留保险)都会被这里捕获,并打印异常类型名 + 描述。
else: 只有 try 块里没有抛出任何异常时才会进来,打印计算结果 y
finally: 无论前面是否出现异常、是否被捕获,都会执行;通常放“必须收尾”的代码,如释放文件、网络连接、打印日志等。
  • type(e).__name__:拿到异常对象 e 的实际类名(字符串),例如 IndexErrorValueErrorKeyError 等。

示例2

从文件读取数字并计算平方根,全程捕获并报告异常。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import math
import os

def sqrt_from_file():
    file_path = input("请输入文件路径:").strip()
    try:
        if not os.path.exists(file_path):
            raise FileNotFoundError("文件不存在")
        with open(file_path, "r", encoding="utf-8") as f:
            content = f.readline().strip()
            num = float(content)
        if num < 0:
            raise ValueError("不能对负数开平方")
        root = math.sqrt(num)
    except FileNotFoundError as e:
        print("文件级错误:", e)
    except ValueError as e:
        print("数据格式错误:", e)
    except Exception as e:
        print("未捕获的异常:", type(e).__name__, e)
    else:
        print(f"√{num} = {root:.4f}")
    finally:
        print("--- 无论成功与否,都会执行 finally ---")

sqrt_from_file()

功能说明:

  1. 让用户输入文件路径。
  2. 检查文件是否存在,不存在则主动抛出并捕获 FileNotFoundError
  3. 读取文件第一行内容并转为浮点数,若格式非法则捕获 ValueError
  4. 若数字为负,主动抛出并捕获 ValueError,提示“不能对负数开平方”。
  5. 若一切正常,计算并打印平方根。
  6. 无论是否发生异常,最后都会打印一条“无论成功与否,都会执行 finally”的提示。

综合练习

练习1

【课堂小练习】 异常处理练习1:读取指定文件并求和

要求:

编写一个程序,实现以下功能:

手动创建文件num.txt,内容如下:

1
2
3
4
5
6
7
12
34.23
67
-98
23.31
-67.21
78
  1. 读取文件内容,计算文件中所有数字的总和(每行一个数字)。
  2. 使用 try...except...else...finally 结构处理以下异常情况:
    • 文件 num.txt 不存在时,捕获 FileNotFoundError,并打印提示:“文件 num.txt 不存在,请创建该文件并确保其路径正确。”
    • 文件内容中存在非数字行时,捕获 ValueError,并打印提示:“文件内容格式错误,所有行必须是数字。”
  3. 如果文件读取和计算都成功,打印总和,格式为:“文件内数字总和为:xxx”。
  4. 无论是否发生异常,finally 块中都要打印:“文件操作结束,程序执行完毕。”

8 爬虫案例:抓取豆瓣高分电影并保存 CSV

导读

  1. 目标:一键拿到「豆瓣高分」最新 Top100 电影清单
    • 包括片名、评分、评分人数、年份、国家/地区、类型 6 大关键信息。
  2. 方法:直接调用豆瓣移动端未公开的开放接口(无需登录、无 Cookie)
    • 通过 1 行 HTTP GET 请求即可批量返回 100 条数据。
  3. 流程:请求 → 解析 → 排序 → 落盘
    • 10 行核心代码完成网络请求与 JSON 解析;
    • 按评分从高到低排序,保证榜单即看即用;
    • 自动写入本地 CSV(UTF-8 编码),Excel/Numbers 直接双击打开。
  4. 结果:得到 douban_top100.csv
    • 可做个人观影指南、数据可视化原始素材,或喂给推荐算法做冷启动。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 安装依赖
# pip install requests pandas -i https://pypi.tuna.tsinghua.edu.cn/simple

import csv
import requests

# 请求配置
url = "http://m.douban.com/rexxar/api/v2/subject/recent_hot/movie"
params = {"limit": 100, "category": "豆瓣高分", "type": "全部", "ck": "tVS3"}
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Referer": "https://movie.douban.com/ "
}

# 2. 发送请求
print("网络请求中...")
resp = requests.get(url, params=params, headers=headers, timeout=10)
resp.raise_for_status()  # 非 200 直接抛异常
print(f"下载完成,状态码:{resp.status_code}")

# 3. 解析 JSON
data = resp.json()
items = data.get("items", [])
rows = [["电影名称", "评分", "评分人数", "年份", "国家", "类型"]]  # 表头

for item in items:
    card = item.get("card_subtitle", "").split("/")
    card = [c.strip() for c in card]
    year = card[0] if len(card) > 0 else ""
    country = card[1] if len(card) > 1 else ""
    genre = card[2] if len(card) > 2 else ""

    rows.append([
        item.get("title", ""),
        item.get("rating", {}).get("value") or 0,
        item.get("rating", {}).get("count") or 0,
        year,
        country,
        genre
    ])

# 4. 排序 & 保存(跳过表头排序)
rows[1:] = sorted(rows[1:], key=lambda x: x[1], reverse=True)  # 按评分排序

output_file = f"douban_top{len(rows)-1}.csv"

with open(output_file, 'w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerows(rows)
print(f"已保存 {len(rows)-1} 部电影到 {output_file}")

课后练习

  1. params 里的 limit 改成 200,看豆瓣是不是只返 100(接口封顶)。
  2. 把排序关键字换成“评分人数”,找“评分人数最多但分数 < 8.0”的奇葩电影。
  3. 如果返回 418 “I’m a teapot”,尝试加 cookiestime.sleep() 降速。

结语

本章你学会了:

  • Python 安装、缩进、注释、变量、类型;
  • 字符串、列表、字典、元组、集合的“增删改查”;
  • 条件、循环、函数、模块、文件、异常;
  • 一个爬虫案例:抓取豆瓣电影。

下一章我们将引入 BeautifulSoup + XPath,真正解析 HTML 网页,把“肉眼可见”的数据统统抓下来!

0%