Python(一)

31 阅读35分钟

Python 基础语法学习笔记(上篇:基础 ~ 函数 ~ 模块)

涵盖 Python 基础语法、数据类型、流程控制、数据容器、函数、模块六大板块。


目录

  • 第一章:初识 Python(01-05)
    • 1.1 Hello World 与 print 输出
    • 1.2 字面量
    • 1.3 变量
    • 1.4 标识符与字符串格式化
    • 1.5 键盘输入 input()
  • 第二章:流程控制
    • 2.1 条件语句 if / elif / else
    • 2.2 模式匹配 match / case(Python 3.10+)
    • 2.3 for 循环
    • 2.4 while 循环
    • 2.5 for 与 while 对比
    • 2.6 循环控制语句 break / continue / pass
    • 2.7 while...else / for...else
    • 2.8 嵌套循环与 99 乘法表
    • 2.9 综合案例:猜数字游戏
  • 第三章:数据容器(08-18)
    • 3.1 列表 list
    • 3.2 字符串常用方法
    • 3.3 元组 tuple
    • 3.4 集合 set
    • 3.5 字典 dict
    • 3.6 综合案例
    • 3.7 列表推导式(List Comprehension)
    • 3.8 深拷贝与浅拷贝(面试高频)
  • 第四章:函数(19-27)
    • 4.1 函数基础
    • 4.2 函数进阶
    • 4.3 Lambda 匿名函数
    • 4.4 递归
    • 4.5 类型注解
    • 4.6 装饰器(Decorator)
    • 4.7 迭代器与生成器
    • 4.8 常用内置函数速查
  • 第五章:模块与包(28-32)
    • 5.1 模块的概念与导入方式
    • 5.2 name 与 all
    • 5.3 包(Package)

第一章:初识 Python(01-05)

1.1 Hello World 与 print 输出

# 这是注释
print("Hello World")
print("Hello Python")

核心知识点:

知识点说明
print()Python 内置输出函数,将内容打印到控制台
#单行注释标记,# 后面的内容不会被执行
字符串用引号包裹的文本,单引号 '...' 或双引号 "..." 均可
换行拼接使用 \n 换行符 + + 运算符拼接多行字符串

变量定义与拼接输出示例:

line1 = "###########"
line2 = "#   白日依山尽   #"
# 用换行符拼接所有行并输出
print(line1 + "\n" + line2)

1.2 字面量

字面量是代码中直接写出的固定值,Python 支持以下字面量类型:

类型关键字示例说明
整数int100没有小数点的数字
浮点数float3.14带小数点的数字
布尔值boolTrue / False逻辑真/假
字符串str"hello python"文本数据
空值NoneTypeNone表示"什么都没有"

重要特性:布尔值可以参与运算

print(100 + True)   # 输出 101(True 被当作 1)
print(100 + False)  # 输出 100(False 被当作 0)

1.3 变量

变量是程序中用来存储数据的容器。

定义格式:

变量名 = 值

核心特性:

num = 114.1          # 定义变量
num = num + 11       # 可以重新计算
num = "hello world"  # Python 是动态类型,变量可以改变数据类型

批量定义多个变量:

first, two = 12, 13  # 一行定义多个变量
print(first, two)     # 输出:12 13

1.4 标识符与字符串格式化

标识符是为变量、函数、类等元素所起的名字。

字符串格式化两种方式:

方式一:% 占位符(传统方式)

name = "张三"
age = 18
print("大家好,我是%s, 今年%s岁" % (name, age))

常用占位符:

占位符说明
%s字符串
%d整数
%f浮点数

方式二:f-string(推荐,Python 3.6+)

name = "张三"
age = 18
print(f"大家好,我是{name}, 今年{age}岁")

f-string 可以直接在 {} 中嵌入变量名或表达式,更直观、更推荐。


1.5 键盘输入 input()

name = input("请输入您的姓名:")
age = input("请输入您的年龄: ")
print(f"您的姓名是{name}, 年龄为{age}")

关键注意事项:

  • input() 返回的永远是字符串 str 类型
  • 如果需要数字,必须手动转换:int(input("请输入数字: "))
  • input() 会阻塞程序,等待用户输入后才继续执行

第二章:流程控制

流程控制是指通过特定的语句来改变代码的执行顺序,使程序能够根据不同条件做出不同的判断,或者重复执行某些操作。Python 中有三大类流程控制语句:条件语句、循环语句、循环控制语句。

2.1 条件语句 if / elif / else

条件语句用于根据不同的条件执行不同的代码块。

2.1.1 语法定义
# 形式一:单条件
if 条件:
    代码块

# 形式二:二选一
if 条件:
    代码块A
else:
    代码块B

# 形式三:多条件分支
if 条件1:
    代码块A
elif 条件2:
    代码块B
elif 条件3:
    代码块C
else:
    代码块D  # 以上条件都不满足时执行

语法规则:

要点说明
if必须有,是条件判断的入口
elif可选,可以有多个,是 else if 的缩写
else可选,最多一个,兜底分支
条件任何能产生布尔值(True/False)的表达式
缩进Python 用缩进(通常 4 个空格)表示代码块,不用花括号 {}
冒号 :每个分支条件后面必须加 :
2.1.2 基础示例
score = 85

if score >= 90:
    print("优秀")
elif score >= 80:
    print("良好")      # ← 命中这里
elif score >= 60:
    print("及格")
else:
    print("不及格")
2.1.3 条件表达式(三元运算符)

当只有两个分支且每个分支只有一条赋值语句时,可以简写:

# 标准写法
if age >= 18:
    status = "成年"
else:
    status = "未成年"

# 三元运算符简写
status = "成年" if age >= 18 else "未成年"
2.1.4 使用场景
场景示例
成绩等级判定根据分数范围输出 A/B/C/D
用户权限判断管理员/普通用户/游客看到不同菜单
数据校验检查输入是否合法,给出不同提示
游戏逻辑血量 > 0 继续游戏,否则 Game Over
2.1.5 条件中的运算符
# 比较运算符
x == y    # 等于
x != y    # 不等于
x > y     # 大于
x < y     # 小于
x >= y    # 大于等于
x <= y    # 小于等于

# 逻辑运算符
a and b   # 与:两个都为 True 才为 True
a or b    # 或:至少一个为 True 就为 True
not a     # 非:取反

# 成员运算符
x in [1, 2, 3]       # x 是否在列表中
x not in "hello"     # x 是否不在字符串中

综合示例:

age = 25
has_ticket = True

if age >= 18 and has_ticket:
    print("可以入场")
elif age >= 18 and not has_ticket:
    print("请先购票")
else:
    print("未成年人需家长陪同")

2.2 模式匹配 match / case(Python 3.10+)

Python 3.10 引入了 match/case 语句,功能类似于其他语言的 switch/case,但更强大。

2.2.1 语法定义
match 目标值:
    case 模式1:
        代码块1
    case 模式2:
        代码块2
    case _:
        兜底代码块  # 相当于 else / default

语法规则:

要点说明
match后面跟要被匹配的目标值(变量、表达式等)
case每个分支定义一个匹配模式
_通配符,匹配任何值,相当于 default / else,放在最后
无需 break匹配成功后自动跳出,不会"穿透"到下一个 case
缩进与 if/for/while 一样,用缩进表示代码块
2.2.2 基础示例 — 等值匹配
command = "start"

match command:
    case "start":
        print("启动程序")
    case "stop":
        print("停止程序")
    case "pause":
        print("暂停程序")
    case _:
        print(f"未知命令: {command}")

与 if/elif 的等价对比:

# if/elif 写法
if command == "start":
    print("启动程序")
elif command == "stop":
    print("停止程序")
elif command == "pause":
    print("暂停程序")
else:
    print(f"未知命令: {command}")

# match/case 写法(更简洁清晰)
match command:
    case "start":
        print("启动程序")
    case "stop":
        print("停止程序")
    case "pause":
        print("暂停程序")
    case _:
        print(f"未知命令: {command}")
2.2.3 多值匹配

一个 case 可以匹配多个值,用 | 分隔:

http_status = 404

match http_status:
    case 200:
        print("OK")
    case 301 | 302:
        print("重定向")
    case 404:
        print("未找到")
    case 500 | 502 | 503:
        print("服务器错误")
    case _:
        print("未知状态码")
2.2.4 带条件的匹配(Guard)

在 case 后面加 if 条件,实现更精细的匹配:

score = 85

match True:
    case _ if score >= 90:
        print("优秀")
    case _ if score >= 80:
        print("良好")     # ← 命中
    case _ if score >= 60:
        print("及格")
    case _:
        print("不及格")
2.2.5 解构匹配(match/case 的独有能力)

match/case 比普通 switch 更强大,可以直接解构数据结构:

# 解构元组
point = (0, 5)

match point:
    case (0, 0):
        print("原点")
    case (0, y):
        print(f"在 Y 轴上,y={y}")    # ← 命中
    case (x, 0):
        print(f"在 X 轴上,x={x}")
    case (x, y):
        print(f"普通点 ({x}, {y})")
# 解构列表
coords = [1, 2, 3]

match coords:
    case [x]:
        print(f"一维: {x}")
    case [x, y]:
        print(f"二维: ({x}, {y})")
    case [x, y, z]:
        print(f"三维: ({x}, {y}, {z})")  # ← 命中
2.2.6 使用场景
场景说明
菜单/命令分发根据用户输入的命令执行不同操作
HTTP 状态码处理不同状态码对应不同处理逻辑
数据结构解构根据数据的形状/内容执行不同分支
状态机根据当前状态决定下一步行为
替代长串 if/elif多个等值判断时,比 if/elif 更清晰
2.2.7 match/case vs if/elif 选择建议
情况推荐
简单的等值判断(3 个以上分支)match/case
需要解构数据结构match/case(if 做不到)
复杂的范围/条件判断if/elif
只有 2 个分支if/else 更简洁
Python 版本 < 3.10只能用 if/elif

2.3 for 循环

for 循环用于遍历一个可迭代对象(如列表、字符串、元组、range 等),逐个取出元素进行处理。

2.3.1 语法定义
for 变量 in 可迭代对象:
    循环体代码

语法规则:

要点说明
for ... in固定语法,从可迭代对象中逐个取出元素
变量每次循环自动赋值为当前取出的元素
可迭代对象列表、元组、字符串、字典、range() 等
循环次数由可迭代对象的元素个数决定,遍历完自动结束
2.3.2 基础示例
# 遍历列表
fruits = ["苹果", "香蕉", "橘子"]
for fruit in fruits:
    print(fruit)

# 遍历字符串
for char in "Python":
    print(char, end=" ")  # 输出:P y t h o n

# 遍历字典
scores = {"张三": 85, "李四": 92, "王五": 78}
for name, score in scores.items():
    print(f"{name}: {score}分")
2.3.3 range() 函数

range() 常与 for 搭配,用于生成数字序列,控制循环次数。

range(stop)          # 生成 0 到 stop-1
range(start, stop)   # 生成 start 到 stop-1
range(start, stop, step)  # 指定步长
# 循环 5 次
for i in range(5):
    print(i)  # 0, 1, 2, 3, 4

# 指定范围
for i in range(1, 6):
    print(i)  # 1, 2, 3, 4, 5

# 指定步长(偶数)
for i in range(0, 10, 2):
    print(i)  # 0, 2, 4, 6, 8

# 倒序
for i in range(5, 0, -1):
    print(i)  # 5, 4, 3, 2, 1
2.3.4 使用场景
场景示例
遍历数据容器逐个处理列表、字典中的元素
固定次数循环重复执行 N 次操作
生成数字序列配合 range() 产生序号、编号
嵌套循环打印表格、乘法表、图形

2.4 while 循环

while 循环在条件为 True 时持续执行,适合不确定循环次数、但知道终止条件的场景。

2.4.1 语法定义
while 条件:
    循环体代码

语法规则:

要点说明
条件每次循环前都会判断,为 True 则继续,为 False 则退出
死循环如果条件永远为 True,循环永远不会结束(需配合 break)
更新变量循环体内通常要有改变条件的操作,否则容易死循环
2.4.2 基础示例
# 计数循环
count = 1
while count <= 5:
    print(f"第 {count} 次")
    count += 1  # 每次加 1,最终使条件变为 False

# 用户输入验证
password = ""
while password != "123456":
    password = input("请输入密码: ")
print("登录成功!")
2.4.3 while True 无限循环
while True:
    cmd = input("请输入命令(输入 q 退出): ")
    if cmd == "q":
        break       # 满足条件时跳出循环
    print(f"执行命令: {cmd}")
2.4.4 使用场景
场景示例
不确定循环次数持续读取用户输入,直到输入特定值
菜单系统反复显示菜单,等待用户选择
游戏主循环持续运行直到玩家退出
轮询/等待等待某个条件成立(如文件就绪、网络连通)

2.5 for 与 while 对比

对比项for 循环while 循环
适用场景已知遍历目标或循环次数只知道终止条件,不知道次数
遍历能力直接遍历容器元素需要手动管理索引
死循环风险低(遍历完自动结束)高(条件不变就永远循环)
典型用法for i in range(10):while count < 100:
# 同样的功能,两种写法对比

# for:遍历列表(推荐)
names = ["张三", "李四", "王五"]
for name in names:
    print(name)

# while:需要手动管理索引
names = ["张三", "李四", "王五"]
i = 0
while i < len(names):
    print(names[i])
    i += 1

2.6 循环控制语句 break / continue / pass

这三个语句用于在循环内部精细控制执行流程。

2.6.1 break — 立即终止整个循环
# 在 1-10 中找到第一个能被 7 整除的数
for i in range(1, 11):
    if i % 7 == 0:
        print(f"找到了: {i}")
        break  # 找到后立刻退出循环,不再继续

执行流程:

i=1 → 不满足 → i=2 → 不满足 → ... → i=7 → 满足 → print → break → 循环结束
2.6.2 continue — 跳过本次,进入下一次
# 打印 1-10 中的奇数(跳过偶数)
for i in range(1, 11):
    if i % 2 == 0:
        continue  # 跳过本次循环的剩余代码,直接进入下一次
    print(i)  # 只输出 1, 3, 5, 7, 9

执行流程:

i=1 → 奇数 → print(1)
i=2 → 偶数 → continue → 跳到 i=3
i=3 → 奇数 → print(3)
...
2.6.3 pass — 空操作占位符

pass 什么都不做,仅用于保持语法完整(某些地方必须有代码才能运行)。

# 场景一:暂时未实现的分支
for i in range(10):
    if i < 5:
        pass  # TODO: 以后再补充逻辑
    else:
        print(i)

# 场景二:定义空类或空函数
class MyFutureClass:
    pass  # 以后再填充内容

def my_future_function():
    pass  # 以后再填充内容
2.6.4 break 与 continue 对比
对比项breakcontinue
作用终止整个循环跳过本次循环
后续执行不再执行任何迭代继续下一次迭代
使用场景找到目标后立刻停止过滤掉不需要的元素
# break:找到第一个偶数就停止
for n in [1, 3, 5, 4, 7, 8]:
    if n % 2 == 0:
        print(f"找到偶数: {n}")
        break
# 输出:找到偶数: 4

# continue:跳过所有偶数
for n in [1, 3, 5, 4, 7, 8]:
    if n % 2 == 0:
        continue
    print(n, end=" ")
# 输出:1 3 5 7

2.7 while...else / for...else

Python 独有的语法:循环正常结束(没有被 break)时,执行 else 块。

# for...else:检查列表中是否有负数
numbers = [1, 5, 8, 10, 15]

for n in numbers:
    if n < 0:
        print("发现负数!")
        break
else:
    # 循环没有被 break 中断时执行
    print("所有数字都是正数")
情况else 是否执行
循环正常结束执行
循环被 break 中断不执行

2.8 嵌套循环与 99 乘法表

for i in range(1, 10):           # 外层循环 - 控制行
    for j in range(1, i + 1):    # 内层循环 - 控制列
        print(f"{j} x {i} = {j * i}", end="\t")
    print()  # 换行

知识点拆解:

知识点说明
range(start, end)生成从 start 到 end-1 的整数序列
end="\t"print() 默认以换行结尾,end="\t" 改为以制表符结尾
嵌套循环外层循环每执行一次,内层循环完整执行一轮

输出效果:

1 x 1 = 1
1 x 2 = 2   2 x 2 = 4
1 x 3 = 3   2 x 3 = 6   3 x 3 = 9
...

2.9 综合案例:猜数字游戏

这是一个综合了 random、while、if/elif/else、try/except 的小游戏。

import random

target_number = random.randint(1, 100)  # 生成 1-100 的随机整数

while True:
    try:
        user_guess = int(input("请输入你猜的数字: "))
    except ValueError:
        print("输入无效,请输入一个整数!")
        continue

    if user_guess > target_number:
        print("猜大了!再试一次。")
    elif user_guess < target_number:
        print("猜小了!再试一次。")
    else:
        print(f"恭喜你!猜对了,答案就是 {target_number}!")
        break

涉及知识点:

知识点说明
random.randint(a, b)生成 [a, b] 范围内的随机整数
while True无限循环,配合 break 退出
if / elif / else条件分支判断
try / except ValueError捕获用户输入非数字时的异常
break跳出当前循环
continue跳过本次循环,进入下一次

第三章:数据容器(08-18)

3.1 列表 list

列表是 Python 中最常用的数据容器,有序、可修改、可重复、可存储不同类型。

3.1.1 定义与基本操作
s = [100, 120, "hello", "o", 'l', 90, 9, True]
操作语法说明
访问元素s[0]通过索引获取,索引从 0 开始
修改元素s[1] = 150直接赋值修改
删除元素del s[1]删除指定索引的元素
遍历for item in s:逐个取出元素
切片s[0:2:1][起始:结束:步长]

切片详解:

l = ["A", "B", "C", "D", "E", "F", "G"]
l[0:2:1]   # ['A', 'B']    从索引 0 到 1(不含 2),步长 1
l[:2]       # ['A', 'B']    省略起始默认为 0
l[:5:2]     # ['A', 'C', 'E']  从 0 到 4,步长 2
3.1.2 列表常用方法
s = [53, 23, 76, 100, 10, 32]
方法说明示例
append(x)在末尾添加元素s.append(900)
insert(i, x)在指定位置插入s.insert(0, 111)
remove(x)移除第一个匹配的值s.remove(23)
pop(i)删除并返回指定索引元素s.pop(0)
sort()升序排序s.sort()
reverse()反转列表s.reverse()

3.2 字符串常用方法

s = " hello-Python-Hello-World "
方法说明示例结果
find(sub)查找子串首次出现的索引,找不到返回 -1s.find("-") → 6
count(sub)统计子串出现次数s.count("o") → 3
upper()全部转大写"HELLO-PYTHON..."
lower()全部转小写" hello-python..."
split(sep)按分隔符截取,返回列表s.split("-") → [' hello', 'Python', ...]
strip()去除两端空白字符"hello-Python-Hello-World"
replace(old, new)替换字符串s.replace("-", "_")
startswith(prefix)是否以指定子串开头s.startswith("hello") → False(前面有空格)

邮箱验证案例:

email = input("请输入一个邮箱地址: ")
if email.count('@') == 1 and '.' in email:
    print("邮箱格式正确")
else:
    print("邮箱格式错误")

3.3 元组 tuple

元组是不可变的序列,创建后不能修改,只能查询。

3.3.1 定义与基本操作
t1 = (10, 20, 30, 40, 50, 30)
操作语法说明
索引访问t1[0]获取第一个元素
负索引t1[-1]获取最后一个元素
切片t1[0:2:1]与列表切片语法一致
count(x)统计元素出现次数t1.count(30) → 2
index(x)查找元素首次出现的索引t1.index(30) → 2

定义单元素元组时必须加逗号:

t2 = (100,)   # 注意末尾的逗号
print(type(t2))  # <class 'tuple'>
3.3.2 元组组包与解包
# 组包:将多个值打包成元组
t1 = (10, 20, 30, 40, 50, 60, 99, 100)
t2 = 10, 20, 30, 40  # 省略括号也可以

# 解包:将元组元素分别赋值给多个变量
a, b, c, d = t2

# * 收集剩余的所有元素
e, f, *other, g = t1
print(other)  # [30, 40, 50, 60, 99]

# 经典用法:交换两个变量
a1, b1 = 10, 20
a1, b1 = b1, a1  # a1=20, b1=10

3.4 集合 set

集合是无序、不重复的数据容器,天然支持去重和集合运算。

3.4.1 定义与基本操作
s1 = {"hello", 5, 243, 12, 0, 5}  # 自动去重,5 只会出现一次
s2 = set()                          # 定义空集合(不能用 {},那是空字典)
方法说明
add(x)添加元素
remove(x)移除指定元素
pop()随机删除并返回一个元素
clear()清空集合
3.4.2 集合运算
s5 = {"A", "B", "C", "D", "E", "F", "G"}
s6 = {"A", "B", "C", "D"}
运算方法运算符说明
差集s5.difference(s6)s5 - s6在 s5 但不在 s6 中的元素
并集s5.union(s6)s5 | s6两个集合的所有元素(去重)
交集s5.intersection(s6)s5 & s6两个集合共有的元素

课程选修案例:

football_set = {"王林", "曾牛", "徐立国", ...}
basketball_set = {"张铁", "王林", "曾牛", ...}

# 同时选修足球和篮球的学生
both = football_set & basketball_set

# 选修足球但没选修篮球的学生
only_football = football_set - basketball_set

# 所有选修了任意课程的学生
all_students = football_set | basketball_set

3.5 字典 dict

字典存储键值对(key: value),通过 key 快速查找 value。

核心特点:

  • key 不能重复(重复会被覆盖)
  • key 必须是不可变类型(字符串、数字、元组可以;列表不行)
  • value 可以是任意类型
  • Python 3.7+ 字典保持插入顺序
3.5.1 定义与基本操作
dict1 = {"王林": 456, "李慕婉": 234, "韩立": 542, "徐立国": 210}
操作语法说明
取值dict1["王林"]key 不存在会报错 KeyError
安全取值dict1.get("王林")key 不存在返回 None(不报错)
修改dict1["王林"] = 700key 存在则覆盖
添加dict1["新key"] = valuekey 不存在则新增
删除del dict1["key"]删除指定键值对
弹出dict1.pop("key")删除并返回 value
3.5.2 遍历
# 遍历所有键值对(最常用)
for k, v in dict1.items():
    print(f"key为{k}; 值为{v}")

# 只遍历 key
for k in dict1.keys():
    print(k)

# 只遍历 value
for v in dict1.values():
    print(v)

3.6 综合案例

学生成绩管理系统

使用列表嵌套元组存储数据,综合运用循环、解包、格式化输出:

students = [
    ("S001", "王林", 85, 92, 78),
    ("S002", "李嘉婧", 92, 88, 95),
    ...
]

# 元组解包提取数据
for stu in students:
    sid, name, chinese, math, english = stu
    total = chinese + math + english
    avg = total / 3
    print(f"{sid:<6} {name:<6} {chinese:<6} {math:<6} {english:<6} {total:<6} {avg:.2f}")
购物车管理系统

使用字典嵌套字典实现完整的增删改查:

shopping_cart = {}
# 结构: { "商品名称": {"price": 价格, "quantity": 数量} }

# 添加商品
shopping_cart[name] = {"price": price, "quantity": quantity}

# 格式化输出对齐
print(f"{'商品名称':<15} {'商品价格':<15} {'商品数量':<10}")
print(f"{name:<15} ¥{info['price']:<14.2f} {info['quantity']:<10}")

3.7 列表推导式(List Comprehension)

列表推导式是 Python 最具特色的语法之一,用一行代码从已有序列生成新列表。

基本语法
# 语法:[表达式 for 变量 in 可迭代对象 if 条件]

# 传统写法:生成 1~10 的平方列表
squares = []
for x in range(1, 11):
    squares.append(x ** 2)

# 列表推导式:一行搞定
squares = [x ** 2 for x in range(1, 11)]
print(squares)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
带条件过滤
# 筛选偶数
evens = [x for x in range(1, 21) if x % 2 == 0]
print(evens)  # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# 筛选长度大于 3 的字符串
words = ["hi", "hello", "ok", "python", "yes"]
long_words = [w for w in words if len(w) > 3]
print(long_words)  # ['hello', 'python']
if-else 三元表达式
# 偶数标记 "E",奇数标记 "O"
labels = ["E" if x % 2 == 0 else "O" for x in range(1, 6)]
print(labels)  # ['O', 'E', 'O', 'E', 'O']

# 成绩评级
scores = [88, 55, 72, 93, 41]
grades = ["及格" if s >= 60 else "不及格" for s in scores]
print(grades)  # ['及格', '不及格', '及格', '及格', '不及格']
嵌套推导式
# 展平二维列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
print(flat)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# 生成坐标组合
coords = [(x, y) for x in range(3) for y in range(3) if x != y]
print(coords)  # [(0,1),(0,2),(1,0),(1,2),(2,0),(2,1)]
字典推导式 & 集合推导式
# 字典推导式
names = ["alice", "bob", "charlie"]
name_lengths = {name: len(name) for name in names}
print(name_lengths)  # {'alice': 5, 'bob': 3, 'charlie': 7}

# 集合推导式(自动去重)
numbers = [1, 2, 2, 3, 3, 3, 4]
unique_squares = {x ** 2 for x in numbers}
print(unique_squares)  # {1, 4, 9, 16}
推导式 vs map/filter 对比
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 筛选偶数并求平方
# 推导式(推荐,更直观)
result = [x ** 2 for x in numbers if x % 2 == 0]

# map + filter(函数式风格)
result = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, numbers)))

面试提示: 列表推导式比等价的 map + filter 更快(因为不需要函数调用),且可读性更好。


3.8 深拷贝与浅拷贝(面试高频)

Python 中赋值只是传递引用,拷贝分为浅拷贝和深拷贝,区别在于是否递归复制嵌套对象。

赋值 vs 浅拷贝 vs 深拷贝
import copy

original = [[1, 2, 3], [4, 5, 6]]

# 赋值:只是多了一个引用,完全共享
assignment = original

# 浅拷贝:复制外层容器,内层嵌套对象仍是引用
shallow = copy.copy(original)
# 等价写法:
shallow2 = original[:]        # 列表切片
shallow3 = list(original)     # list() 构造
shallow4 = original.copy()    # .copy() 方法

# 深拷贝:递归复制所有层级
deep = copy.deepcopy(original)
关键区别:修改嵌套元素
import copy

original = [[1, 2], [3, 4]]
shallow  = copy.copy(original)
deep     = copy.deepcopy(original)

# 修改外层元素
original.append([5, 6])
print(shallow)  # [[1, 2], [3, 4]]     ← 浅拷贝不受影响
print(deep)     # [[1, 2], [3, 4]]     ← 深拷贝不受影响

# 修改内层嵌套元素
original[0][0] = 999
print(shallow)  # [[999, 2], [3, 4]]   ← 浅拷贝跟着变了!内层是共享引用
print(deep)     # [[1, 2], [3, 4]]     ← 深拷贝不受影响
内存图解
原始对象 original = [[1,2], [3,4]]
                    ┌──────────────┐
                    │  外层列表 ID_A │
                    │  [ref_B, ref_C]│
                    └──────┬───────┘
                 ┌─────────┴─────────┐
            ┌────▼────┐        ┌─────▼────┐
            │ [1, 2]  │        │ [3, 4]   │
            │  ID_B   │        │  ID_C    │
            └─────────┘        └──────────┘

浅拷贝 shallow = copy.copy(original)
  → 新建外层列表 ID_D,但内部仍引用 ID_B、ID_C

深拷贝 deep = copy.deepcopy(original)
  → 新建外层列表 ID_E + 新建内层列表 ID_F、ID_G(全部复制)
对比总结表
操作语法外层容器嵌套对象性能
赋值b = a共享引用共享引用最快(零开销)
浅拷贝copy.copy(a) / a[:] / a.copy()复制新对象共享引用较快
深拷贝copy.deepcopy(a)复制新对象递归复制较慢(有递归开销)
浅拷贝够用的场景
# 一维列表(无嵌套)浅拷贝即可
nums = [1, 2, 3, 4, 5]
nums_copy = nums[:]
nums_copy[0] = 999
print(nums)       # [1, 2, 3, 4, 5]  不受影响
print(nums_copy)  # [999, 2, 3, 4, 5]
必须用深拷贝的场景
import copy

# 嵌套结构(如二维列表、字典嵌套)
matrix = [[1, 2], [3, 4]]
matrix_copy = copy.deepcopy(matrix)
matrix_copy[0][0] = 999
print(matrix[0][0])       # 1(不受影响)

# 实际案例:配置模板
default_config = {
    "database": {"host": "localhost", "port": 3306},
    "features": ["auth", "logging"]
}

# 为不同环境创建独立配置
dev_config  = copy.deepcopy(default_config)
prod_config = copy.deepcopy(default_config)

dev_config["database"]["host"] = "127.0.0.1"
prod_config["database"]["host"] = "10.0.0.1"
# 三者互不影响
面试陷阱题
a = [1, [2, 3]]
b = a.copy()       # 浅拷贝
b[0] = 100         # 修改外层 → a 不受影响
b[1].append(4)     # 修改内层 → a 也受影响!

print(a)  # [1, [2, 3, 4]]  ← 内层列表是共享的!
print(b)  # [100, [2, 3, 4]]

记忆口诀: 浅拷贝只抄外壳,深拷贝连 internals 一起克隆。一维数据用切片,嵌套结构用 deepcopy。


第四章:函数(19-27)

4.1 函数基础

函数是一段可以反复调用的代码块,用于提高代码复用性。

定义语法:

def 函数名(参数列表):
    """文档字符串(可选)"""
    函数体
    return 返回值  # 可选

示例:

# 无参数函数
def out_line():
    print("--------------")

# 带参数和返回值
def circle_area(r):
    area = 3.14 * r * r
    return area

# 带文档字符串
def rectangle_area(l, w):
    """
    计算长方体面积
    :param l: 长度
    :param w: 宽度
    :return: 长方体面积
    """
    return l * w

函数练习:

# 计算三角形面积
def calculate_triangle_area(base, height):
    return base * height / 2

# 计算元音字母个数
def count_vowels(text):
    vowels = "aeiouAEIOU"
    count = 0
    for char in text:
        if char in vowels:
            count += 1
    return count

# 分析成绩(返回多个值)
def analyze_scores(scores):
    return max(scores), min(scores), round(sum(scores) / len(scores), 1)

4.2 函数进阶

4.2.1 变量作用域
num = 100  # 全局变量

def circle_area(r):
    pi = 3.14  # 局部变量,函数外部不可访问
    print("函数内部", num)  # 可以读取全局变量
    return pi * r * r
作用域说明
全局变量定义在函数外部,所有函数都能读取
局部变量定义在函数内部,只在函数内有效
4.2.2 关键字参数
def reg_stu(name, age, gender, city):
    print(f"姓名:{name}, 年龄:{age}, 性别:{gender}, 城市:{city}")

# 关键字参数:可以不按顺序,但位置参数必须在关键字参数之前
reg_stu(name="张三", age=18, gender="男", city="北京")
reg_stu("赵四", 28, gender="男", city="上海")  # 混合使用
4.2.3 不定长参数 *args 和 **kwargs(面试必考)

核心概念:

参数类型收集内容数据结构
*args位置参数所有未匹配的位置参数tuple(元组)
**kwargs关键字参数所有未匹配的关键字参数dict(字典)

基础用法:

def demo(*args, **kwargs):
    print(f"args  = {args}")       # 元组
    print(f"kwargs = {kwargs}")    # 字典

demo(1, 2, "hello", name="Bob", score=99.5)
# args  = (1, 2, 'hello')
# kwargs = {'name': 'Bob', 'score': 99.5}

参数定义顺序规则(面试常考):

# 正确的参数顺序:
def func(普通参数, *args, 关键字参数=默认值, **kwargs):
    pass

# 示例
def register(name, *hobbies, city="未知", **extra):
    print(f"姓名: {name}")
    print(f"爱好: {hobbies}")      # 元组
    print(f"城市: {city}")
    print(f"其他: {extra}")        # 字典

register("张三", "篮球", "音乐", city="北京", age=20)
# 姓名: 张三
# 爱好: ('篮球', '音乐')
# 城市: 北京
# 其他: {'age': 20}

参数解包(调用时):

def add(a, b, c):
    return a + b + c

# 列表/元组解包为位置参数
nums_list = [1, 2, 3]
print(add(*nums_list))       # 6  等价于 add(1, 2, 3)

nums_tuple = (10, 20, 30)
print(add(*nums_tuple))      # 60

# 字典解包为关键字参数
params = {"a": 1, "b": 2, "c": 3}
print(add(**params))         # 6  等价于 add(a=1, b=2, c=3)

实际应用场景:

# 场景一:通用日志函数
def log(level, message, *args, **kwargs):
    """支持格式化参数的日志"""
    if args:
        message = message % args
    if kwargs:
        message = message.format(**kwargs)
    print(f"[{level}] {message}")

log("INFO", "用户 %s 登录成功", "张三")
log("WARN", "磁盘使用率 {pct}%", pct=85)

# 场景二:装饰器中转发参数
def timer(func):
    def wrapper(*args, **kwargs):
        import time
        start = time.time()
        result = func(*args, **kwargs)  # 原样转发
        print(f"{func.__name__} 耗时 {time.time() - start:.2f}s")
        return result
    return wrapper

# 场景三:计算任意数量参数的和
def flexible_sum(*args):
    """接收任意数量的数字并求和"""
    return sum(args)

print(flexible_sum(1, 2, 3))          # 6
print(flexible_sum(10, 20, 30, 40))   # 100

只有关键字参数 / 只有关置参数(Python 3.8+):

# * 后面的参数必须用关键字方式传递
def connect(host, port, *, timeout=30, retry=3):
    print(f"连接 {host}:{port},超时={timeout},重试={retry}")

connect("localhost", 3306)                    # OK
connect("localhost", 3306, timeout=60)        # OK
# connect("localhost", 3306, 60)              # TypeError!

# / 前面的参数只能用位置方式传递
def power(x, /, n=2):
    return x ** n

power(3)        # OK → 9
power(3, 3)     # OK → 27
# power(x=3)    # TypeError! x 不能用关键字
4.2.4 综合案例:订单金额计算
def calculate_order_total(products, coupon_discount=0, points=0, shipping_fee=0):
    total_price = sum(item['price'] * item['quantity'] for item in products)

    # 优惠券:满5000可用,不超过商品总价
    valid_coupon = min(coupon_discount, total_price) if total_price >= 5000 else 0

    # 积分:满5000可用,100积分=1元,整百抵扣
    points_money = (points // 100) * 1 if total_price >= 5000 else 0

    final_amount = total_price - valid_coupon - points_money + shipping_fee
    return {"商品总价": total_price, "应付总额": max(0, final_amount), ...}

4.3 Lambda 匿名函数

Lambda 是一种简洁的匿名函数,只能包含一个表达式。

语法:

lambda 参数: 表达式

各种参数形式:

# 无参数
say_hello = lambda: print("Hello!")

# 默认参数
power = lambda x, n=2: x ** n

# 不定长参数
sum_all = lambda *args: sum(args)

核心应用场景 — 配合高阶函数:

data_list = [1, 5, 2, 8, 3]

# map(): 对每个元素进行操作
doubled = list(map(lambda x: x * 2, data_list))       # [2, 10, 4, 16, 6]

# filter(): 过滤元素
filtered = list(filter(lambda x: x > 3, data_list))    # [5, 8]

# sorted(): 自定义排序
students = [("张三", 88), ("李四", 95), ("王五", 72)]
sorted_students = sorted(students, key=lambda s: s[1], reverse=True)
# [("李四", 95), ("张三", 88), ("王五", 72)]

4.4 递归

递归是函数在内部调用自身,必须有终结点,否则会无限递归导致栈溢出。

def jc(n):
    """计算 n 的阶乘"""
    if n == 1:           # 终结点(基准情况)
        return 1
    else:
        return n * jc(n - 1)  # 递归调用

print(jc(10))  # 3628800

递归三要素:

  1. 终结点(base case):什么时候停止递归
  2. 递归调用:函数调用自身
  3. 递进关系:每次调用都向终结点靠近

4.5 类型注解

类型注解不影响运行,但能提高代码可读性和 IDE 提示。

变量类型注解:

a: int = 695
score: float = 98.5
hobby: str = "Python"
names: list[str] = ["A", "C", "E"]
phones: set[str] = {"13309091111"}
options: dict[str, int] = {"count": 0, "total": 0}
goods: tuple[str, int, int] = ("手机", 5999, 1)

函数类型注解:

def calc(scores: list[int]) -> float:
    """计算平均分"""
    return sum(scores) / len(scores)

def calc_data(scores: list[int]) -> tuple[int, int, float]:
    """返回 (最高分, 最低分, 平均分)"""
    return max(scores), min(scores), sum(scores) / len(scores)

4.6 装饰器(Decorator)

装饰器是 Python 的高级特性,用于在不修改原函数代码的前提下,给函数增加额外功能。本质是一个接收函数作为参数、并返回新函数的高阶函数。

4.6.1 语法定义
def 装饰器函数(原函数):
    def 包装函数(*args, **kwargs):
        # 调用前的额外操作
        result = 原函数(*args, **kwargs)
        # 调用后的额外操作
        return result
    return 包装函数

@装饰器函数
def 被装饰的函数():
    pass

@装饰器函数 是语法糖,等价于 被装饰的函数 = 装饰器函数(被装饰的函数)。

4.6.2 基础示例 — 计时装饰器
import time

def timer(func):
    """计算函数执行耗时的装饰器"""
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行耗时: {end - start:.4f} 秒")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)
    return "完成"

slow_function()
# 输出:slow_function 执行耗时: 1.0012 秒
4.6.3 带参数的装饰器
def repeat(n):
    """让函数重复执行 n 次"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hello(name):
    print(f"Hello, {name}!")

say_hello("张三")
# Hello, 张三!
# Hello, 张三!
# Hello, 张三!
4.6.4 常用内置装饰器
装饰器说明使用场景
@staticmethod静态方法,不需要 self 或 cls工具函数,与实例/类无关
@classmethod类方法,第一个参数是 cls工厂方法、访问类属性
@property将方法变成属性访问getter/setter 封装
@functools.lru_cache缓存函数返回值递归、重复计算优化
from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    """带缓存的斐波那契,避免重复计算"""
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(100))  # 瞬间完成,因为有缓存
4.6.5 使用场景
场景说明
日志记录自动记录函数调用信息
性能计时统计函数执行耗时
权限校验调用前检查用户权限
缓存结果避免重复计算(如 @lru_cache)
重试机制失败后自动重试 N 次

4.7 迭代器与生成器

4.7.1 可迭代对象与迭代器
概念定义判断方式
可迭代对象(Iterable)实现了 __iter__() 方法的对象,可以被 for 循环遍历isinstance(obj, Iterable)
迭代器(Iterator)实现了 __iter__() 和 __next__() 方法的对象,可以逐个取值直到耗尽isinstance(obj, Iterator)
from collections.abc import Iterable, Iterator

# 列表是可迭代对象,但不是迭代器
lst = [1, 2, 3]
print(isinstance(lst, Iterable))   # True
print(isinstance(lst, Iterator))   # False

# 调用 iter() 后变成迭代器
it = iter(lst)
print(isinstance(it, Iterator))    # True
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# print(next(it))  # 抛出 StopIteration

常见可迭代对象: list、tuple、str、dict、set、range()、文件对象

4.7.2 生成器函数(yield)

生成器是一种特殊的迭代器,用 yield 关键字定义,按需生成值,节省内存。

def count_up(n):
    """从 1 数到 n"""
    i = 1
    while i <= n:
        yield i
        i += 1

# 生成器不会一次性计算所有值,而是每次调用 next() 时才生成一个
gen = count_up(5)
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3

# 也可以用 for 循环遍历
for num in count_up(5):
    print(num, end=" ")  # 1 2 3 4 5

生成器 vs 列表对比:

# 列表:一次性占用全部内存
big_list = [x ** 2 for x in range(1000000)]     # 立即分配 100 万个元素的内存

# 生成器:按需生成,几乎不占内存
big_gen = (x ** 2 for x in range(1000000))      # 生成器表达式,几乎不占内存
对比项列表生成器
语法[x for x in range(n)](x for x in range(n)) 或 yield
内存一次性加载全部数据按需生成,占用极小
取值可索引 lst[0]只能逐个 next()
遍历可多次遍历只能遍历一次(耗尽即空)
适用场景数据量小、需要随机访问数据量大、只需顺序访问
4.7.3 生成器的典型应用
# 读取大文件(不会一次性加载到内存)
def read_large_file(file_path):
    with open(file_path, "r", encoding="utf-8") as f:
        for line in f:
            yield line.strip()

for line in read_large_file("big_data.txt"):
    print(line)

# 无限序列
def infinite_counter(start=0):
    while True:
        yield start
        start += 1

counter = infinite_counter()
print(next(counter))  # 0
print(next(counter))  # 1
print(next(counter))  # 2

4.8 常用内置函数速查

4.8.1 类型与转换
函数说明示例
type(obj)返回对象的类型type(123) → <class 'int'>
isinstance(obj, cls)判断对象是否是指定类型的实例isinstance(123, int) → True
int(x)转换为整数int("42") → 42
float(x)转换为浮点数float("3.14") → 3.14
str(x)转换为字符串str(100) → "100"
bool(x)转换为布尔值bool(0) → False
list(x)转换为列表list("abc") → ['a','b','c']
tuple(x)转换为元组tuple([1,2,3]) → (1,2,3)
set(x)转换为集合set([1,1,2]) → {1,2}
dict(x)转换为字典dict([("a",1),("b",2)]) → {"a":1,"b":2}
4.8.2 数学与序列操作
函数说明示例
abs(x)绝对值abs(-5) → 5
round(x, n)四舍五入到 n 位小数round(3.1415, 2) → 3.14
max(...)最大值max(1,5,3) → 5
min(...)最小值min([2,7,4]) → 2
sum(iterable)求和sum([1,2,3]) → 6
len(obj)返回元素个数len("hello") → 5
pow(base, exp)幂运算pow(2, 10) → 1024
divmod(a, b)返回商和余数的元组divmod(7, 3) → (2, 1)
4.8.3 序列操作
函数说明示例
sorted(iterable)排序,返回新列表sorted([3,1,2]) → [1,2,3]
reversed(seq)反转,返回迭代器list(reversed([1,2,3])) → [3,2,1]
enumerate(iterable)同时获取索引和值for i, v in enumerate(["a","b"]):
zip(*iterables)将多个序列打包成元组zip([1,2], ["a","b"]) → (1,"a"),(2,"b")
range(start, stop, step)生成数字序列range(0, 10, 2) → 0,2,4,6,8
slice(start, stop)切片对象s = slice(0, 3); lst[s]
# enumerate 示例
fruits = ["苹果", "香蕉", "橘子"]
for i, fruit in enumerate(fruits, start=1):
    print(f"{i}. {fruit}")
# 1. 苹果
# 2. 香蕉
# 3. 橘子

# zip 示例
names = ["张三", "李四", "王五"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
    print(f"{name}: {score}分")
4.8.4 函数式编程
函数说明示例
map(func, iterable)对每个元素应用函数list(map(str, [1,2,3])) → ['1','2','3']
filter(func, iterable)过滤满足条件的元素list(filter(lambda x: x>0, [-1,2,-3])) → [2]
sorted(iterable, key=func)按自定义规则排序sorted(students, key=lambda s: s[1])
4.8.5 其他常用
函数说明示例
print(*args, sep, end)输出到控制台print("a", "b", sep="-") → a-b
input(prompt)读取键盘输入(返回 str)name = input("姓名: ")
id(obj)返回对象的内存地址id(x)
hash(obj)返回对象的哈希值hash("hello")
callable(obj)判断对象是否可调用callable(print) → True
help(obj)显示帮助文档help(len)
dir(obj)列出对象的所有属性和方法dir(str)
open(file, mode)打开文件open("data.txt", "r")

第五章:模块与包(28-32)

5.1 模块的概念与导入方式

模块就是一个 .py 文件,里面可以包含函数、类、变量等,可以被其他文件导入使用。

五种导入方式:

# 1. 导入整个模块
import random

# 2. 给模块起别名
import random as rd

# 3. 从模块中导入指定功能
from random import randint

# 4. 导入模块中的所有功能(不推荐)
from random import *

# 5. 导入并给功能起别名
from random import randint as ri

5.2 __name__ 与 __all__

__name__:模块的身份证
if __name__ == "__main__":
    # 只有直接运行此文件时才执行
    # 被其他文件 import 时不会执行
    print("测试代码")
场景__name__ 的值
直接运行文件"__main__"
被其他文件导入模块文件名(如 "my_function")
__all__:导出白名单
__all__ = ["PI", "log_separator1", "log_separator2"]

当别人使用 from module import * 时,只有 __all__ 中列出的名字才能被导入。


5.3 包(Package)

包本质上就是一个包含 __init__.py 文件的文件夹,用于管理多个模块。

目录结构:

项目目录/
├── main.py              # 主程序
└── my_package/           # 包
    ├── __init__.py       # 包的标志文件
    ├── add.py            # 模块
    └── sub.py            # 模块

四种导入方式:

# 1. import 包名.模块名
import my_package.add
result = my_package.add.add(10, 5)

# 2. from 包名 import 模块名
from my_package import add, sub
print(add.add(10, 5))

# 3. from 包名.模块名 import 功能名
from my_package.add import add
print(add(20, 30))

# 4. from 包名 import *(不推荐)
from my_package import *

附录:知识点速查表

数据容器对比

特性列表 list元组 tuple集合 set字典 dict
语法[1,2,3](1,2,3){1,2,3}{"k":"v"}
有序是是否是(3.7+)
可修改是否是是
可重复是是否key 不可重复
查找速度O(n)O(n)O(1)O(1)
典型用途通用序列不可变数据去重/集合运算键值映射

字符串格式化对比

方式语法推荐度
% 占位符"name=%s" % name旧式,不推荐
format()"name={}".format(name)兼容旧版本
f-stringf"name={name}"最推荐

函数参数类型

参数类型语法说明
位置参数def f(a, b)按顺序传入
关键字参数f(a=1, b=2)按名称传入
默认参数def f(a, b=10)不传则用默认值
不定长位置def f(*args)接收为元组
不定长关键字def f(**kwargs)接收为字典