Python 语法完全指南:从零到进阶
本文系统介绍 Python 语法,从基础到进阶,每个语法点都配有详细示例和练习题,帮助你快速掌握 Python 编程。
目录
- 一、最基础:运行 & print
- 二、变量与基本数据类型
- 三、容器类型:list / tuple / dict / set
- 四、运算符
- 五、流程控制:if / for / while
- 六、函数(def)& 默认参数 / 可变参数
- 七、模块与包(import)
- 八、异常处理 try / except / finally
- 九、面向对象(类 / 继承 / 属性)
- 十、列表推导式 & 生成器表达式
- 十一、迭代器 & 生成器函数(yield)
- 十二、lambda & 内置高阶函数
- 十三、装饰器(decorator)
- 十四、上下文管理器(with)& 文件操作
- 十五、类型注解(type hints)
- 十六、异步编程(async / await)
- 十七、常用内置函数 & 语法糖补充
一、最基础:运行 & print
1.1 第一个 Python 程序
创建文件:创建一个 .py 文件(如 hello.py)
# hello.py
print("Hello, Python")
print("欢迎学习 Python!")
运行方式:
# 命令行运行
python hello.py
# 或
python3 hello.py
输出结果:
Hello, Python
欢迎学习 Python!
1.2 print 函数详解
基本用法:
# 打印字符串
print("Hello")
# 打印多个值(自动用空格分隔)
print("Hello", "World", "Python")
# 自定义分隔符
print("Hello", "World", sep="-") # 输出: Hello-World
# 自定义结束符(默认是换行)
print("Hello", end="")
print("World") # 输出: HelloWorld(不换行)
# 格式化输出
name = "Tom"
age = 20
print(f"姓名: {name}, 年龄: {age}") # f-string(推荐)
print("姓名: {}, 年龄: {}".format(name, age)) # format 方法
print("姓名: %s, 年龄: %d" % (name, age)) # % 格式化(旧式)
1.3 Python 代码规范
缩进规则:
- Python 使用缩进来表示代码块(其他语言用
{}) - 标准缩进是 4 个空格(不要用 Tab,除非配置了 Tab = 4 空格)
- 同一代码块必须使用相同的缩进
# 正确示例
if True:
print("这是 if 代码块")
print("缩进相同")
# 错误示例(会报错)
if True:
print("缩进不一致")
print("这行会报错:IndentationError")
注释:
# 单行注释
"""
多行注释
可以用三个双引号
或三个单引号
"""
'''
这也是多行注释
'''
1.4 练习题
练习 1.1:编写程序,打印你的姓名、年龄和爱好(使用 f-string)
name = "张三"
age = 25
hobby = "编程"
print(f"姓名: {name}") # 姓名: 张三
print(f"年龄: {age}") # 年龄: 25
print(f"爱好: {hobby}") # 爱好: 编程
练习 1.2:使用 print 打印一个简单的表格(姓名、年龄、城市)
print("姓名\t年龄\t城市")
print("-" * 20)
print("张三\t25\t北京")
print("李四\t30\t上海")
print("王五\t28\t广州")
# 输出结果:
# 姓名 年龄 城市
# --------------------
# 张三 25 北京
# 李四 30 上海
# 王五 28 广州
二、变量与基本数据类型
2.1 变量基础
变量命名规则:
- 只能包含字母、数字和下划线
- 不能以数字开头
- 区分大小写
- 不能使用 Python 关键字(如
if,for,def等)
# 正确命名
name = "Tom"
age = 20
user_name = "admin"
_name = "private" # 下划线开头(约定为私有变量)
# 错误命名
# 2name = "Tom" # 不能以数字开头
# user-name = "Tom" # 不能使用连字符
# if = 10 # 不能使用关键字
变量赋值:
# 单个赋值
x = 10
name = "Tom"
# 多重赋值
a, b, c = 1, 2, 3
x = y = z = 0 # 所有变量都赋值为 0
# 交换变量值(Python 特色)
a, b = b, a # 无需临时变量
动态类型:
# Python 是动态类型语言,变量类型可以改变
x = 10 # x 是 int
x = "hello" # x 现在是 str
x = [1, 2, 3] # x 现在是 list
2.2 数字类型
整数(int):
# 基本整数
a = 10
b = -5
c = 0
# 大整数(Python 3 没有 long 类型,int 可以无限大)
big_num = 123456789012345678901234567890
# 不同进制
binary = 0b1010 # 二进制,值为 10
octal = 0o12 # 八进制,值为 10
hexadecimal = 0xA # 十六进制,值为 10
# 类型转换
str_num = "123"
int_num = int(str_num) # 字符串转整数
浮点数(float):
# 基本浮点数
pi = 3.14
negative = -2.5
scientific = 1.23e4 # 科学计数法,值为 12300.0
# 精度问题(注意)
result = 0.1 + 0.2
print(result) # 0.30000000000000004(浮点数精度问题)
# 类型转换
int_to_float = float(10) # 10.0
str_to_float = float("3.14") # 3.14
复数(complex):
# 复数(科学计算用)
c = 3 + 4j
c = complex(3, 4) # 等价写法
print(c.real) # 实部:3.0
print(c.imag) # 虚部:4.0
2.3 字符串类型
字符串创建:
# 三种引号都可以
s1 = "双引号"
s2 = '单引号'
s3 = """三引号可以
跨多行"""
# 转义字符
s = "他说:\"你好\"" # 他说:"你好"
s = "第一行\n第二行" # \n 换行
s = "路径:C:\\Users" # \\ 表示反斜杠
s = r"C:\Users" # 原始字符串(raw string),不转义
# f-string(Python 3.6+,推荐)
name = "Tom"
age = 20
s = f"姓名: {name}, 年龄: {age}" # 姓名: Tom, 年龄: 20
# 表达式
s = f"10 + 20 = {10 + 20}" # 10 + 20 = 30
字符串常用操作:
s = "Python Programming"
# 长度
len(s) # 18
# 大小写转换
s.lower() # 'python programming'
s.upper() # 'PYTHON PROGRAMMING'
s.capitalize() # 'Python programming'
s.title() # 'Python Programming'
# 查找和替换
s.find("Pro") # 7(返回索引,找不到返回 -1)
s.index("Pro") # 7(返回索引,找不到抛异常)
s.replace("Python", "Java") # 'Java Programming'
# 分割和连接
s.split() # ['Python', 'Programming'](按空格分割)
s.split("n") # ['Pytho', ' Programm', 'g']
",".join(["a", "b", "c"]) # 'a,b,c'
# 去除空白
" hello ".strip() # 'hello'
" hello ".lstrip() # 'hello '
" hello ".rstrip() # ' hello'
# 判断
s.startswith("Py") # True
s.endswith("ing") # True
s.isdigit() # False(是否全为数字)
s.isalpha() # False(是否全为字母)
# 索引和切片
s[0] # 'P'(第一个字符)
s[-1] # 'g'(最后一个字符)
s[0:6] # 'Python'(切片:从索引 0 到 6,不包含 6)
s[:6] # 'Python'(从开头到索引 6)
s[7:] # 'Programming'(从索引 7 到结尾)
s[::2] # 'Pto rgamn'(步长为 2)
s[::-1] # 'gnimmargorP nohtyP'(反转字符串)
2.4 布尔类型
# 布尔值
is_true = True
is_false = False
# 布尔运算
result = True and False # False
result = True or False # True
result = not True # False
# 其他类型转布尔
bool(1) # True(非零数字为 True)
bool(0) # False
bool("") # False(空字符串为 False)
bool("abc") # True(非空字符串为 True)
bool([]) # False(空列表为 False)
bool([1,2]) # True(非空列表为 True)
bool(None) # False(None 为 False)
# 布尔值在条件判断中的应用
if name: # 等价于 if name != "" and name is not None
print("有名字")
2.5 None 类型
# None 表示"无值"或"空值"
value = None
# 检查是否为 None
if value is None:
print("值为空")
# None 与其他值的比较
None == None # True
None is None # True(推荐用 is 比较)
2.6 类型检查和转换
# 类型检查
type(10) # <class 'int'>
type("hello") # <class 'str'>
isinstance(10, int) # True(推荐用 isinstance)
# 类型转换
int("123") # 123
float("3.14") # 3.14
str(123) # '123'
bool(1) # True
list("abc") # ['a', 'b', 'c']
tuple([1, 2, 3]) # (1, 2, 3)
2.7 练习题
练习 2.1:创建一个变量存储你的信息(姓名、年龄、城市),并用 f-string 格式化输出
name = "张三"
age = 25
city = "北京"
print(f"姓名: {name}, 年龄: {age}, 城市: {city}")
练习 2.2:编写程序,计算圆的面积(半径 = 5,π = 3.14159)
radius = 5
pi = 3.14159
area = pi * radius ** 2
print(f"半径为 {radius} 的圆的面积是: {area:.2f}")
练习 2.3:字符串操作练习
- 给定字符串
" Hello, World! " - 去除首尾空格
- 转换为小写
- 替换 "World" 为 "Python"
- 反转字符串
s = " Hello, World! "
print(f"原始字符串: '{s}'") # 原始字符串: ' Hello, World! '
s = s.strip() # 去除首尾空格
print(f"去除空格后: '{s}'") # 去除空格后: 'Hello, World!'
s = s.lower() # 转小写
print(f"转小写后: '{s}'") # 转小写后: 'hello, world!'
s = s.replace("world", "python") # 替换
print(f"替换后: '{s}'") # 替换后: 'hello, python!'
s = s[::-1] # 反转
print(f"反转后: '{s}'") # 反转后: '!nohtyp ,olleh'
三、容器类型:list / tuple / dict / set
Python 提供了四种常用的容器类型,用于存储多个数据。
3.1 列表 list(可变、有序)
特点:有序、可变、可重复元素
创建列表:
# 空列表
empty = []
empty = list()
# 包含元素的列表
nums = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True] # 可以混合类型
nested = [[1, 2], [3, 4]] # 嵌套列表
访问元素:
nums = [10, 20, 30, 40, 50]
# 索引访问(从 0 开始)
nums[0] # 10(第一个元素)
nums[2] # 30(第三个元素)
nums[-1] # 50(最后一个元素)
nums[-2] # 40(倒数第二个)
# 切片(slice)
nums[1:3] # [20, 30](索引 1 到 2,不包含 3)
nums[:3] # [10, 20, 30](前三个)
nums[2:] # [30, 40, 50](从索引 2 开始)
nums[::2] # [10, 30, 50](步长为 2)
nums[::-1] # [50, 40, 30, 20, 10](反转)
修改列表:
nums = [1, 2, 3]
# 添加元素
nums.append(4) # [1, 2, 3, 4](末尾添加)
nums.insert(1, 10) # [1, 10, 2, 3, 4](索引 1 处插入)
nums.extend([5, 6]) # [1, 10, 2, 3, 4, 5, 6](扩展列表)
# 修改元素
nums[0] = 100 # [100, 10, 2, 3, 4, 5, 6]
# 删除元素
nums.remove(10) # 删除第一个值为 10 的元素
del nums[0] # 删除索引 0 的元素
nums.pop() # 删除并返回最后一个元素
nums.pop(1) # 删除并返回索引 1 的元素
列表常用方法:
nums = [3, 1, 4, 1, 5, 9, 2, 6]
# 查找
nums.index(4) # 2(返回第一个 4 的索引)
nums.count(1) # 2(统计 1 出现的次数)
4 in nums # True(检查元素是否存在)
# 排序
nums.sort() # 原地排序:[1, 1, 2, 3, 4, 5, 6, 9]
nums.sort(reverse=True) # 降序排序
sorted_nums = sorted(nums) # 返回新列表,不修改原列表
# 反转
nums.reverse() # 原地反转
reversed_nums = nums[::-1] # 返回新列表
# 长度
len(nums) # 8
遍历列表:
nums = [1, 2, 3, 4, 5]
# 方式 1:直接遍历元素
for num in nums:
print(num)
# 方式 2:遍历索引
for i in range(len(nums)):
print(f"索引 {i}: {nums[i]}")
# 方式 3:同时获取索引和值(推荐)
for i, num in enumerate(nums):
print(f"索引 {i}: {num}")
# 方式 4:列表推导式(后面会讲)
squares = [x**2 for x in nums]
3.2 元组 tuple(不可变、有序)
特点:有序、不可变、可重复元素(一旦创建不能修改)
创建元组:
# 空元组
empty = ()
empty = tuple()
# 包含元素的元组
point = (10, 20)
single = (42,) # 注意:单个元素需要逗号
mixed = (1, "hello", 3.14)
# 也可以不用括号(不推荐)
point = 10, 20
访问元素:
point = (10, 20, 30)
point[0] # 10
point[-1] # 30
point[1:3] # (20, 30)(切片)
解包(unpacking):
# 基本解包
x, y = (10, 20)
print(x, y) # 10 20
# 扩展解包
first, *middle, last = (1, 2, 3, 4, 5)
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
# 交换变量(元组解包的应用)
a, b = 10, 20
a, b = b, a # 交换:a=20, b=10
元组常用操作:
t = (1, 2, 3, 2, 4)
len(t) # 5
t.count(2) # 2(统计元素出现次数)
t.index(3) # 2(返回元素索引)
3 in t # True
# 元组不可变,但可以连接
t1 = (1, 2)
t2 = (3, 4)
t3 = t1 + t2 # (1, 2, 3, 4)
使用场景:
- 作为字典的键(因为不可变)
- 函数返回多个值
- 保护数据不被修改
3.3 字典 dict(键值对,无序)
特点:键值对存储、无序(Python 3.7+ 保持插入顺序)、键必须不可变
创建字典:
# 空字典
empty = {}
empty = dict()
# 包含键值对
user = {
"name": "Tom",
"age": 20,
"city": "Beijing"
}
# 使用 dict() 构造函数
user = dict(name="Tom", age=20)
user = dict([("name", "Tom"), ("age", 20)])
访问和修改:
user = {"name": "Tom", "age": 20}
# 访问
user["name"] # 'Tom'
user.get("age") # 20
user.get("email", "N/A") # 'N/A'(键不存在时返回默认值)
# 修改
user["age"] = 21 # 修改值
user["email"] = "tom@example.com" # 添加新键值对
# 删除
del user["age"] # 删除键值对
email = user.pop("email") # 删除并返回值
user.clear() # 清空字典
字典常用方法:
user = {"name": "Tom", "age": 20, "city": "Beijing"}
# 获取所有键、值、键值对
user.keys() # dict_keys(['name', 'age', 'city'])
user.values() # dict_values(['Tom', 20, 'Beijing'])
user.items() # dict_items([('name', 'Tom'), ('age', 20), ...])
# 转换为列表
list(user.keys()) # ['name', 'age', 'city']
# 检查键是否存在
"name" in user # True
"email" in user # False
# 更新字典
user.update({"age": 21, "email": "tom@example.com"})
# 长度
len(user) # 3
遍历字典:
user = {"name": "Tom", "age": 20, "city": "Beijing"}
# 遍历键
for key in user:
print(key, user[key])
# 遍历键值对(推荐)
for key, value in user.items():
print(f"{key}: {value}")
# 遍历值
for value in user.values():
print(value)
字典推导式:
# 创建平方字典
squares = {x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 过滤
even_squares = {x: x**2 for x in range(5) if x % 2 == 0}
# {0: 0, 2: 4, 4: 16}
3.4 集合 set(去重、无序)
特点:无序、不重复、可变(frozenset 不可变)
创建集合:
# 空集合(注意:不能用 {},那是空字典)
empty = set()
# 包含元素的集合
s = {1, 2, 3, 4}
s = set([1, 2, 3, 3, 4]) # {1, 2, 3, 4}(自动去重)
# 从字符串创建
s = set("hello") # {'h', 'e', 'l', 'o'}(去重)
集合操作:
s = {1, 2, 3, 4}
# 添加元素
s.add(5) # {1, 2, 3, 4, 5}
s.update([5, 6, 7]) # {1, 2, 3, 4, 5, 6, 7}
# 删除元素
s.remove(5) # 删除 5,不存在会报错
s.discard(10) # 删除 10,不存在不报错
s.pop() # 删除并返回任意一个元素
s.clear() # 清空集合
# 检查成员
3 in s # True
10 in s # False
集合运算:
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
# 并集
a | b # {1, 2, 3, 4, 5, 6}
a.union(b) # 等价写法
# 交集
a & b # {3, 4}
a.intersection(b) # 等价写法
# 差集
a - b # {1, 2}(在 a 中但不在 b 中)
a.difference(b) # 等价写法
# 对称差集(异或)
a ^ b # {1, 2, 5, 6}(只在其中一个集合中)
a.symmetric_difference(b) # 等价写法
# 子集和超集
{1, 2}.issubset(a) # True
a.issuperset({1, 2}) # True
集合推导式:
# 创建偶数集合
evens = {x for x in range(10) if x % 2 == 0}
# {0, 2, 4, 6, 8}
3.5 容器类型选择指南
| 类型 | 有序 | 可变 | 重复 | 使用场景 |
|---|---|---|---|---|
| list | ✅ | ✅ | ✅ | 需要有序、可修改的序列 |
| tuple | ✅ | ❌ | ✅ | 不可变序列,作为字典键 |
| dict | ✅* | ✅ | ❌键 | 键值对映射 |
| set | ❌ | ✅ | ❌ | 去重、集合运算 |
*Python 3.7+ 字典保持插入顺序
3.6 练习题
练习 3.1:列表操作
- 创建一个包含 1-10 的列表
- 计算列表所有元素的和
- 找出列表中的最大值和最小值
- 将列表反转
# 创建列表
nums = list(range(1, 11)) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 计算和
total = sum(nums)
print(f"和: {total}") # 55
# 最大值和最小值
print(f"最大值: {max(nums)}") # 10
print(f"最小值: {min(nums)}") # 1
# 反转
nums.reverse() # 或 nums[::-1]
print(nums) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
练习 3.2:字典操作
- 创建一个学生信息字典(姓名、年龄、成绩)
- 添加新的键值对(班级)
- 遍历并打印所有信息
- 计算平均成绩
# 创建字典
student = {
"name": "张三",
"age": 18,
"scores": [85, 90, 88]
}
# 添加班级
student["class"] = "高三(1)班"
# 遍历打印
for key, value in student.items():
print(f"{key}: {value}")
# 计算平均成绩
avg_score = sum(student["scores"]) / len(student["scores"])
print(f"平均成绩: {avg_score:.2f}") # 87.67
练习 3.3:集合操作
- 有两个列表:
[1, 2, 3, 4, 5]和[4, 5, 6, 7, 8] - 找出它们的交集、并集和差集
a = [1, 2, 3, 4, 5]
b = [4, 5, 6, 7, 8]
set_a = set(a)
set_b = set(b)
# 交集
intersection = set_a & set_b
print(f"交集: {intersection}") # {4, 5}
# 并集
union = set_a | set_b
print(f"并集: {union}") # {1, 2, 3, 4, 5, 6, 7, 8}
# 差集
difference = set_a - set_b
print(f"差集: {difference}") # {1, 2, 3}
练习 3.4:综合练习 编写一个程序,统计一段文本中每个单词出现的次数。
text = "python is great python is fun python is powerful"
# 方法 1:使用字典
word_count = {}
words = text.split()
for word in words:
word_count[word] = word_count.get(word, 0) + 1
print(word_count)
# {'python': 3, 'is': 3, 'great': 1, 'fun': 1, 'powerful': 1}
# 方法 2:使用 collections.Counter(更简洁)
from collections import Counter
word_count = Counter(text.split())
print(dict(word_count))
四、运算符
Python 提供了丰富的运算符,用于各种计算和比较操作。
4.1 算术运算符
# 基本算术运算
a = 10
b = 3
a + b # 13(加法)
a - b # 7(减法)
a * b # 30(乘法)
a / b # 3.333...(除法,返回浮点数)
a // b # 3(整除,向下取整)
a % b # 1(取余/模运算)
a ** b # 1000(幂运算,10 的 3 次方)
# 字符串和列表的运算
"Hello" + " " + "World" # 'Hello World'(字符串连接)
[1, 2] + [3, 4] # [1, 2, 3, 4](列表连接)
"Hi" * 3 # 'HiHiHi'(字符串重复)
[1, 2] * 3 # [1, 2, 1, 2, 1, 2](列表重复)
示例:
# 计算圆的面积
radius = 5
pi = 3.14159
area = pi * radius ** 2
print(f"面积: {area:.2f}") # 面积: 78.54
# 整除和取余的应用
total_minutes = 125
hours = total_minutes // 60 # 2(小时)
minutes = total_minutes % 60 # 5(分钟)
print(f"{hours}小时{minutes}分钟") # 2小时5分钟
4.2 比较运算符
返回布尔值(True/False):
a = 10
b = 20
a == b # False(等于)
a != b # True(不等于)
a < b # True(小于)
a > b # False(大于)
a <= b # True(小于等于)
a >= b # False(大于等于)
# 字符串比较(按字典序)
"apple" < "banana" # True
"abc" == "abc" # True
# 链式比较
5 < 10 < 20 # True(等价于 5 < 10 and 10 < 20)
示例:
# 判断成绩等级
score = 85
if score >= 90:
grade = "优秀"
elif score >= 80:
grade = "良好"
elif score >= 60:
grade = "及格"
else:
grade = "不及格"
print(f"成绩: {score}, 等级: {grade}")
4.3 逻辑运算符
# and(与):两个都为 True 才返回 True
True and True # True
True and False # False
False and False # False
# or(或):至少一个为 True 就返回 True
True or False # True
False or False # False
# not(非):取反
not True # False
not False # True
# 实际应用
age = 20
has_license = True
if age >= 18 and has_license:
print("可以开车")
# 短路求值
x = 0
if x != 0 and 10 / x > 1: # 不会执行除法,因为 x != 0 为 False
print("安全")
示例:
# 判断年份是否为闰年
year = 2024
is_leap = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
print(f"{year}年是闰年: {is_leap}") # True
4.4 成员运算符
# in:检查元素是否在容器中
3 in [1, 2, 3, 4] # True
"py" in "python" # True
"name" in {"name": "Tom"} # True(检查键)
# not in:检查元素是否不在容器中
10 not in [1, 2, 3] # True
示例:
# 检查用户名是否有效
forbidden = ["admin", "root", "test"]
username = "user123"
if username not in forbidden:
print("用户名有效")
else:
print("用户名无效")
4.5 身份运算符
# is:检查两个对象是否是同一个对象(内存地址)
# ==:检查两个对象的值是否相等
a = [1, 2, 3]
b = [1, 2, 3]
c = a
a == b # True(值相等)
a is b # False(不是同一个对象)
a is c # True(是同一个对象)
# 小整数和字符串的缓存(Python 优化)
x = 100
y = 100
x is y # True(小整数被缓存)
# None 的比较
value = None
value is None # True(推荐)
value == None # True(不推荐)
4.6 赋值运算符
x = 10
# 基本赋值
x = 5
# 复合赋值
x += 3 # x = x + 3,结果:8
x -= 2 # x = x - 2,结果:6
x *= 2 # x = x * 2,结果:12
x /= 3 # x = x / 3,结果:4.0
x //= 2 # x = x // 2,结果:2.0
x %= 2 # x = x % 2,结果:0.0
x **= 3 # x = x ** 3,结果:0.0
# 多重赋值
a = b = c = 0 # 三个变量都赋值为 0
x, y = 10, 20 # x=10, y=20
x, y = y, x # 交换 x 和 y
4.7 运算符优先级
从高到低(部分):
()- 括号**- 幂运算*,/,//,%- 乘除+,-- 加减<,<=,>,>=,==,!=- 比较not- 逻辑非and- 逻辑与or- 逻辑或
示例:
# 使用括号明确优先级
result = (2 + 3) * 4 # 20(先算括号)
result = 2 + 3 * 4 # 14(先算乘法)
# 复杂表达式
x = 5
y = 10
z = (x + y) * 2 / 3 # 10.0
4.8 练习题
练习 4.1:算术运算
- 计算
(10 + 5) * 3 - 8 / 2的结果 - 计算 2 的 10 次方
- 将 1234 秒转换为小时、分钟、秒
# 1. 计算表达式
result = (10 + 5) * 3 - 8 / 2
print(f"结果: {result}") # 41.0
# 2. 2 的 10 次方
power = 2 ** 10
print(f"2^10 = {power}") # 1024
# 3. 时间转换
total_seconds = 1234
hours = total_seconds // 3600
minutes = (total_seconds % 3600) // 60
seconds = total_seconds % 60
print(f"{hours}小时{minutes}分钟{seconds}秒") # 0小时20分钟34秒
练习 4.2:逻辑运算 编写程序判断一个数是否在 1-100 之间,且是偶数。
num = 42
# 方法 1
if 1 <= num <= 100 and num % 2 == 0:
print(f"{num} 在 1-100 之间且是偶数")
else:
print(f"{num} 不符合条件")
# 方法 2(更清晰)
is_in_range = 1 <= num <= 100
is_even = num % 2 == 0
if is_in_range and is_even:
print(f"{num} 在 1-100 之间且是偶数")
练习 4.3:成员运算
给定一个列表 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],找出所有能被 3 整除的数。
numbers = list(range(1, 11))
divisible_by_3 = []
for num in numbers:
if num % 3 == 0:
divisible_by_3.append(num)
print(f"能被 3 整除的数: {divisible_by_3}") # [3, 6, 9]
# 或使用列表推导式
divisible_by_3 = [num for num in numbers if num % 3 == 0]
练习 4.4:综合练习 编写一个简单的计算器,支持加、减、乘、除四种运算。
def calculator(a, b, operator):
"""简单计算器"""
if operator == "+":
return a + b
elif operator == "-":
return a - b
elif operator == "*":
return a * b
elif operator == "/":
if b != 0:
return a / b
else:
return "错误:除数不能为 0"
else:
return "错误:不支持的运算符"
# 测试
print(calculator(10, 5, "+")) # 15
print(calculator(10, 5, "-")) # 5
print(calculator(10, 5, "*")) # 50
print(calculator(10, 5, "/")) # 2.0
print(calculator(10, 0, "/")) # 错误:除数不能为 0
五、流程控制:if / for / while
流程控制是编程的核心,用于控制程序的执行顺序。
5.1 条件语句 if / elif / else
基本语法:
# 单分支
if condition:
# 代码块
pass
# 双分支
if condition:
# 条件为 True 时执行
pass
else:
# 条件为 False 时执行
pass
# 多分支
if condition1:
pass
elif condition2:
pass
elif condition3:
pass
else:
pass
示例:
# 判断年龄阶段
age = 20
if age < 18:
print("未成年")
elif age < 60:
print("成年人")
else:
print("老年人")
# 判断成绩等级
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else:
grade = "F"
print(f"成绩: {score}, 等级: {grade}")
# 嵌套 if
x = 10
y = 5
if x > 0:
if y > 0:
print("x 和 y 都大于 0")
else:
print("x > 0 但 y <= 0")
else:
print("x <= 0")
# 简化写法(逻辑运算符)
if x > 0 and y > 0:
print("x 和 y 都大于 0")
三元运算符(条件表达式):
# 基本语法:value_if_true if condition else value_if_false
age = 20
status = "成年人" if age >= 18 else "未成年人"
print(status) # 成年人
# 嵌套使用
score = 85
grade = "优秀" if score >= 90 else "良好" if score >= 80 else "及格" if score >= 60 else "不及格"
print(grade) # 良好
5.2 for 循环
基本语法:
# 遍历序列
for item in sequence:
# 代码块
pass
遍历不同类型:
# 遍历列表
fruits = ["apple", "banana", "orange"]
for fruit in fruits:
print(fruit)
# 遍历字符串
for char in "Python":
print(char)
# 遍历字典
user = {"name": "Tom", "age": 20, "city": "Beijing"}
# 遍历键
for key in user:
print(key, user[key])
# 遍历键值对(推荐)
for key, value in user.items():
print(f"{key}: {value}")
# 遍历值
for value in user.values():
print(value)
range() 函数:
# range(stop):0 到 stop-1
for i in range(5):
print(i) # 0, 1, 2, 3, 4
# range(start, stop):start 到 stop-1
for i in range(2, 5):
print(i) # 2, 3, 4
# range(start, stop, step):指定步长
for i in range(0, 10, 2):
print(i) # 0, 2, 4, 6, 8
# 反向遍历
for i in range(10, 0, -1):
print(i) # 10, 9, 8, ..., 1
enumerate() 函数:
# 同时获取索引和值
fruits = ["apple", "banana", "orange"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 输出:
# 0: apple
# 1: banana
# 2: orange
# 指定起始索引
for index, fruit in enumerate(fruits, start=1):
print(f"{index}: {fruit}")
# 输出:
# 1: apple
# 2: banana
# 3: orange
zip() 函数:
# 并行遍历多个序列
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for name, age in zip(names, ages):
print(f"{name} is {age} years old")
# 输出:
# Alice is 25 years old
# Bob is 30 years old
# Charlie is 35 years old
5.3 while 循环
基本语法:
while condition:
# 代码块
# 需要修改 condition,否则会无限循环
pass
示例:
# 计数循环
count = 0
while count < 5:
print(count)
count += 1
# 输出:0, 1, 2, 3, 4
# 用户输入循环
# while True:
# user_input = input("请输入(输入 'quit' 退出): ")
# if user_input == 'quit':
# break
# print(f"你输入了: {user_input}")
# 计算阶乘
n = 5
factorial = 1
i = 1
while i <= n:
factorial *= i
i += 1
print(f"{n}! = {factorial}") # 120
5.4 break 和 continue
break:跳出循环
# 找到第一个偶数就停止
numbers = [1, 3, 5, 8, 9, 10]
for num in numbers:
if num % 2 == 0:
print(f"找到第一个偶数: {num}")
break
print(f"{num} 是奇数")
# 输出:
# 1 是奇数
# 3 是奇数
# 5 是奇数
# 找到第一个偶数: 8
continue:跳过当前迭代,继续下一次
# 只打印偶数
for num in range(10):
if num % 2 != 0:
continue # 跳过奇数
print(num)
# 输出:0, 2, 4, 6, 8
else 子句(for/while 循环):
# for/while 循环可以带 else,在循环正常结束时执行(不是 break 退出)
for i in range(5):
print(i)
else:
print("循环正常结束")
# 如果 break 退出,else 不执行
for i in range(5):
if i == 3:
break
print(i)
else:
print("这行不会执行")
5.5 嵌套循环
# 打印乘法表
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}×{i}={i*j}", end="\t")
print() # 换行
# 查找二维列表中的元素
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
target = 5
found = False
for row in matrix:
for element in row:
if element == target:
print(f"找到 {target}")
found = True
break
if found:
break
5.6 练习题
练习 5.1:条件语句 编写程序,判断一个年份是否为闰年。
- 能被 4 整除但不能被 100 整除,或者
- 能被 400 整除
year = 2024
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
print(f"{year} 年是闰年")
else:
print(f"{year} 年不是闰年")
# 或使用函数
def is_leap_year(year):
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
print(is_leap_year(2024)) # True
print(is_leap_year(1900)) # False
print(is_leap_year(2000)) # True
练习 5.2:for 循环 计算 1 到 100 之间所有偶数的和。
# 方法 1:使用 range
total = 0
for i in range(2, 101, 2): # 从 2 开始,步长为 2
total += i
print(f"偶数和: {total}") # 2550
# 方法 2:使用 if 判断
total = 0
for i in range(1, 101):
if i % 2 == 0:
total += i
print(f"偶数和: {total}") # 2550
# 方法 3:使用 sum 和 range
total = sum(range(2, 101, 2))
print(f"偶数和: {total}") # 2550
练习 5.3:while 循环 编写一个猜数字游戏:
- 程序随机生成一个 1-100 的数字
- 用户输入猜测的数字
- 提示用户猜大了或猜小了
- 猜对后显示猜了多少次
import random
# 生成随机数
target = random.randint(1, 100)
attempts = 0
print("欢迎来到猜数字游戏!")
print("我已经想好了一个 1-100 之间的数字,试试猜出来吧!")
while True:
try:
guess = int(input("请输入你的猜测: "))
attempts += 1
if guess < target:
print("猜小了!再试试。")
elif guess > target:
print("猜大了!再试试。")
else:
print(f"恭喜你!猜对了!你用了 {attempts} 次。")
break
except ValueError:
print("请输入一个有效的数字!")
练习 5.4:嵌套循环
打印一个由 * 组成的三角形:
*
**
***
****
*****
# 方法 1:使用嵌套循环
n = 5
for i in range(1, n + 1):
for j in range(i):
print("*", end="")
print() # 换行
# 方法 2:使用字符串乘法
n = 5
for i in range(1, n + 1):
print("*" * i)
# 方法 3:使用列表推导式
print("\n".join(["*" * i for i in range(1, 6)]))
练习 5.5:综合练习 编写程序,找出 1-100 之间的所有质数(只能被 1 和自身整除的数)。
def is_prime(n):
"""判断一个数是否为质数"""
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
# 找出所有质数
primes = []
for num in range(2, 101):
if is_prime(num):
primes.append(num)
print(f"1-100 之间的质数: {primes}")
print(f"共有 {len(primes)} 个质数")
六、函数(def) & 默认参数 / 可变参数
函数是组织代码的重要方式,可以重复使用代码块。
6.1 基础函数定义
基本语法:
def function_name(parameters):
"""函数文档字符串(可选)"""
# 函数体
return value # 可选,不写 return 返回 None
示例:
# 简单函数
def greet(name):
print(f"Hello, {name}!")
greet("Tom") # Hello, Tom!
# 带返回值的函数
def add(x, y):
return x + y
result = add(3, 5)
print(result) # 8
# 无返回值函数
def print_info(name, age):
print(f"姓名: {name}, 年龄: {age}")
print_info("Alice", 25) # 姓名: Alice, 年龄: 25
# 多个返回值(返回元组)
def get_name_and_age():
return "Tom", 20
name, age = get_name_and_age()
print(f"{name}, {age}") # Tom, 20
函数文档字符串:
def calculate_area(radius):
"""
计算圆的面积
参数:
radius (float): 圆的半径
返回:
float: 圆的面积
"""
return 3.14159 * radius ** 2
# 查看文档字符串
print(calculate_area.__doc__)
help(calculate_area)
6.2 函数参数
位置参数:
def power(base, exponent):
return base ** exponent
result = power(2, 3) # 8(按位置传递)
关键字参数:
# 使用参数名传递(顺序可以改变)
result = power(exponent=3, base=2) # 8
# 混合使用(位置参数必须在关键字参数之前)
result = power(2, exponent=3) # 8
默认参数:
def greet(name, msg="你好", punctuation="!"):
print(f"{msg}, {name}{punctuation}")
greet("Tom") # 你好, Tom!
greet("Tom", "早上好") # 早上好, Tom!
greet("Tom", "Hi", "?") # Hi, Tom?
# 注意:默认参数必须是不可变对象
# 错误示例
def add_item(item, items=[]): # 危险!
items.append(item)
return items
# 正确做法
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
可变位置参数 *args:
def sum_all(*args):
"""计算所有参数的和"""
total = 0
for num in args:
total += num
return total
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
# args 是一个元组
def print_args(*args):
print(f"参数类型: {type(args)}") # <class 'tuple'>
print(f"参数: {args}")
print_args(1, 2, 3) # 参数: (1, 2, 3)
可变关键字参数 `kwargs`**:
def show_info(**kwargs):
"""打印所有关键字参数"""
for key, value in kwargs.items():
print(f"{key}: {value}")
show_info(name="Tom", age=20, city="Beijing")
# 输出:
# name: Tom
# age: 20
# city: Beijing
# kwargs 是一个字典
def create_user(**kwargs):
user = {}
for key, value in kwargs.items():
user[key] = value
return user
user = create_user(name="Tom", age=20)
print(user) # {'name': 'Tom', 'age': 20}
参数组合:
# 参数顺序:位置参数 -> *args -> 关键字参数 -> **kwargs
def complex_func(a, b, *args, c=10, **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}")
print(f"c={c}")
print(f"kwargs={kwargs}")
complex_func(1, 2, 3, 4, c=20, x=100, y=200)
# 输出:
# a=1, b=2
# args=(3, 4)
# c=20
# kwargs={'x': 100, 'y': 200}
6.3 函数作用域
局部变量和全局变量:
# 全局变量
x = 10
def func():
# 局部变量
y = 20
print(f"局部 y: {y}")
print(f"全局 x: {x}") # 可以读取全局变量
func()
print(f"全局 x: {x}")
# print(y) # 错误:y 是局部变量
# 修改全局变量
def modify_global():
global x # 声明使用全局变量
x = 30
modify_global()
print(x) # 30
nonlocal 关键字:
def outer():
x = 10
def inner():
nonlocal x # 使用外层函数的变量
x = 20
print(f"inner: {x}")
inner()
print(f"outer: {x}")
outer()
# 输出:
# inner: 20
# outer: 20
6.4 Lambda 函数(匿名函数)
# 基本语法:lambda 参数: 表达式
add = lambda x, y: x + y
print(add(3, 5)) # 8
# 常用于高阶函数
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x**2, numbers))
print(squares) # [1, 4, 9, 16, 25]
# 排序
students = [("Alice", 20), ("Bob", 18), ("Charlie", 22)]
students.sort(key=lambda s: s[1]) # 按年龄排序
print(students) # [('Bob', 18), ('Alice', 20), ('Charlie', 22)]
6.5 递归函数
# 计算阶乘
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
# 斐波那契数列
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # 55
# 注意:递归可能导致栈溢出,需要设置递归深度限制
import sys
sys.setrecursionlimit(1000)
6.6 函数作为对象
# 函数可以赋值给变量
def greet(name):
return f"Hello, {name}!"
say_hello = greet
print(say_hello("Tom")) # Hello, Tom!
# 函数可以作为参数传递
def apply_func(func, value):
return func(value)
def square(x):
return x ** 2
result = apply_func(square, 5)
print(result) # 25
# 函数可以作为返回值
def get_multiplier(n):
def multiplier(x):
return x * n
return multiplier
double = get_multiplier(2)
triple = get_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
6.7 练习题
练习 6.1:基础函数 编写一个函数,计算两个数的最大公约数(GCD)。
def gcd(a, b):
"""计算最大公约数(欧几里得算法)"""
while b:
a, b = b, a % b
return a
print(gcd(48, 18)) # 6
print(gcd(100, 25)) # 25
# 递归版本
def gcd_recursive(a, b):
if b == 0:
return a
return gcd_recursive(b, a % b)
print(gcd_recursive(48, 18)) # 6
练习 6.2:默认参数
编写一个函数 format_name,接受姓和名,返回格式化的全名。默认格式为 "名 姓",但可以通过参数改变。
def format_name(first_name, last_name, reverse=False):
"""
格式化姓名
参数:
first_name: 名
last_name: 姓
reverse: 如果为 True,返回 "姓 名",否则返回 "名 姓"
"""
if reverse:
return f"{last_name} {first_name}"
else:
return f"{first_name} {last_name}"
print(format_name("三", "张")) # 三 张
print(format_name("三", "张", True)) # 张 三
练习 6.3:可变参数 编写一个函数,接受任意数量的数字,返回它们的平均值。
def average(*args):
"""计算平均值"""
if len(args) == 0:
return 0
return sum(args) / len(args)
print(average(1, 2, 3, 4, 5)) # 3.0
print(average(10, 20, 30)) # 20.0
print(average()) # 0
练习 6.4:递归函数 编写一个递归函数,计算列表所有元素的和。
def list_sum(lst):
"""递归计算列表和"""
if len(lst) == 0:
return 0
return lst[0] + list_sum(lst[1:])
print(list_sum([1, 2, 3, 4, 5])) # 15
# 更高效的版本(避免切片)
def list_sum_efficient(lst, index=0):
if index >= len(lst):
return 0
return lst[index] + list_sum_efficient(lst, index + 1)
print(list_sum_efficient([1, 2, 3, 4, 5])) # 15
练习 6.5:综合练习
编写一个函数,接受学生信息(使用 **kwargs),返回格式化的学生信息字符串。
def format_student(**kwargs):
"""格式化学生信息"""
required = ["name", "age"]
# 检查必需字段
for field in required:
if field not in kwargs:
return f"错误:缺少必需字段 '{field}'"
# 格式化输出
info = f"姓名: {kwargs['name']}, 年龄: {kwargs['age']}"
# 添加可选字段
if "grade" in kwargs:
info += f", 年级: {kwargs['grade']}"
if "score" in kwargs:
info += f", 成绩: {kwargs['score']}"
return info
print(format_student(name="张三", age=18))
# 姓名: 张三, 年龄: 18
print(format_student(name="李四", age=19, grade="高三", score=95))
# 姓名: 李四, 年龄: 19, 年级: 高三, 成绩: 95
七、模块与包(import)
模块是包含 Python 代码的文件,包是包含多个模块的目录。
7.1 导入标准库
# 导入整个模块
import math
print(math.sqrt(16)) # 4.0
print(math.pi) # 3.141592653589793
# 导入特定函数/类
from datetime import datetime, timedelta
now = datetime.now()
print(now)
# 导入并重命名
import math as m
print(m.sqrt(16))
# 导入所有(不推荐,可能造成命名冲突)
from math import *
print(sqrt(16))
常用标准库:
# os - 操作系统接口
import os
print(os.getcwd()) # 当前工作目录
print(os.listdir('.')) # 列出目录内容
# sys - 系统相关
import sys
print(sys.version) # Python 版本
print(sys.path) # 模块搜索路径
# json - JSON 处理
import json
data = {"name": "Tom", "age": 20}
json_str = json.dumps(data) # 转为 JSON 字符串
data = json.loads(json_str) # 解析 JSON
# random - 随机数
import random
print(random.randint(1, 10)) # 随机整数
print(random.choice([1, 2, 3])) # 随机选择
# datetime - 日期时间
from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(days=1)
7.2 创建和使用模块
文件结构:
myproject/
main.py
utils.py
math_utils.py
utils.py(模块文件):
"""工具函数模块"""
def greet(name):
"""问候函数"""
return f"Hello, {name}!"
def add(x, y):
"""加法函数"""
return x + y
# 模块级别的变量
PI = 3.14159
# 如果直接运行此文件,执行以下代码
if __name__ == "__main__":
print("这是 utils 模块")
print(greet("Test"))
main.py(主程序):
# 导入整个模块
import utils
print(utils.greet("Tom"))
print(utils.add(3, 5))
# 导入特定函数
from utils import greet, add
print(greet("Alice"))
print(add(10, 20))
# 导入并重命名
from utils import greet as say_hello
say_hello("Bob")
7.3 创建包
文件结构:
mypackage/
__init__.py # 包初始化文件(可以是空文件)
module1.py
module2.py
subpackage/
__init__.py
module3.py
init.py(包初始化):
"""mypackage 包"""
# 可以导入子模块,方便使用
from .module1 import function1
from .module2 import function2
# 定义包的版本等
__version__ = "1.0.0"
使用包:
# 导入包中的模块
from mypackage import module1
from mypackage.module2 import function2
# 导入子包
from mypackage.subpackage import module3
7.4 模块搜索路径
import sys
print(sys.path) # Python 搜索模块的路径列表
# 添加自定义路径
sys.path.append('/path/to/your/modules')
7.5 练习题
练习 7.1:创建工具模块
创建一个 string_utils.py 模块,包含以下函数:
reverse_string(s): 反转字符串count_words(s): 统计单词数capitalize_words(s): 每个单词首字母大写
# string_utils.py
def reverse_string(s):
"""反转字符串"""
return s[::-1]
def count_words(s):
"""统计单词数"""
return len(s.split())
def capitalize_words(s):
"""每个单词首字母大写"""
return ' '.join(word.capitalize() for word in s.split())
# 测试
if __name__ == "__main__":
test = "hello world python"
print(reverse_string(test)) # nohtyp dlrow olleh
print(count_words(test)) # 3
print(capitalize_words(test)) # Hello World Python
# main.py
from string_utils import reverse_string, count_words, capitalize_words
text = "python is great"
print(reverse_string(text))
print(count_words(text))
print(capitalize_words(text))
练习 7.2:使用标准库
使用 datetime 模块,编写程序计算两个日期之间的天数差。
from datetime import datetime, date
def days_between(date1_str, date2_str):
"""计算两个日期之间的天数"""
date1 = datetime.strptime(date1_str, "%Y-%m-%d")
date2 = datetime.strptime(date2_str, "%Y-%m-%d")
delta = abs((date2 - date1).days)
return delta
print(days_between("2024-01-01", "2024-12-31")) # 365
# 更简单的方法
def days_between_simple(date1, date2):
"""使用 date 对象"""
return abs((date2 - date1).days)
d1 = date(2024, 1, 1)
d2 = date(2024, 12, 31)
print(days_between_simple(d1, d2)) # 365
八、异常处理 try / except / finally
异常处理让程序在遇到错误时能够优雅地处理,而不是崩溃。
8.1 基本异常处理
try/except:
# 基本语法
try:
# 可能出错的代码
result = 10 / 0
except ZeroDivisionError:
# 处理特定异常
print("不能除以零!")
# 捕获多个异常
try:
num = int(input("请输入数字: "))
result = 10 / num
except ValueError:
print("输入的不是有效数字")
except ZeroDivisionError:
print("不能除以零")
捕获异常对象:
try:
x = 1 / 0
except ZeroDivisionError as e:
print(f"错误: {e}") # 错误: division by zero
print(f"错误类型: {type(e)}") # <class 'ZeroDivisionError'>
捕获所有异常(不推荐,但有时需要):
try:
# 可能出错的代码
result = 10 / 0
except Exception as e:
print(f"发生错误: {e}")
8.2 else 和 finally
else 子句:
try:
result = 10 / 2
except ZeroDivisionError:
print("除零错误")
else:
# 没有异常时执行
print(f"结果: {result}") # 结果: 5.0
finally 子句:
try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("文件不存在")
finally:
# 无论是否发生异常都会执行
print("清理工作")
# file.close() # 确保文件关闭
8.3 常见异常类型
# ValueError - 值错误
try:
int("abc")
except ValueError as e:
print(f"值错误: {e}")
# TypeError - 类型错误
try:
"hello" + 5
except TypeError as e:
print(f"类型错误: {e}")
# IndexError - 索引错误
try:
lst = [1, 2, 3]
print(lst[10])
except IndexError as e:
print(f"索引错误: {e}")
# KeyError - 键错误
try:
d = {"name": "Tom"}
print(d["age"])
except KeyError as e:
print(f"键错误: {e}")
# AttributeError - 属性错误
try:
"hello".append("x")
except AttributeError as e:
print(f"属性错误: {e}")
8.4 抛出异常
raise 语句:
def check_age(age):
if age < 0:
raise ValueError("年龄不能为负数")
if age > 150:
raise ValueError("年龄不能超过 150")
return True
try:
check_age(-5)
except ValueError as e:
print(f"错误: {e}") # 错误: 年龄不能为负数
重新抛出异常:
try:
x = 1 / 0
except ZeroDivisionError:
print("捕获到异常,重新抛出")
raise # 重新抛出异常
8.5 自定义异常
# 定义自定义异常
class NegativeNumberError(Exception):
"""负数错误"""
pass
class TooLargeError(Exception):
"""数值过大错误"""
def __init__(self, value, max_value):
self.value = value
self.max_value = max_value
self.message = f"值 {value} 超过了最大值 {max_value}"
super().__init__(self.message)
# 使用自定义异常
def check_number(num, max_val=100):
if num < 0:
raise NegativeNumberError("不能是负数")
if num > max_val:
raise TooLargeError(num, max_val)
return True
try:
check_number(150, 100)
except NegativeNumberError as e:
print(f"负数错误: {e}")
except TooLargeError as e:
print(f"过大错误: {e}") # 过大错误: 值 150 超过了最大值 100
8.6 异常处理最佳实践
# 1. 具体捕获异常,不要用裸露的 except
# 不好
try:
do_something()
except: # 捕获所有异常,包括系统退出
pass
# 好
try:
do_something()
except (ValueError, TypeError) as e:
print(f"错误: {e}")
# 2. 使用 finally 确保资源清理
def read_file(filename):
file = None
try:
file = open(filename, "r")
return file.read()
except FileNotFoundError:
print(f"文件 {filename} 不存在")
return None
finally:
if file:
file.close()
# 3. 使用 with 语句(上下文管理器,见后面章节)
with open("data.txt", "r") as f:
content = f.read()
# 自动关闭文件
8.7 练习题
练习 8.1:基础异常处理 编写一个安全的除法函数,处理除零错误和类型错误。
def safe_divide(a, b):
"""安全除法"""
try:
result = a / b
return result
except ZeroDivisionError:
return "错误:除数不能为 0"
except TypeError:
return "错误:参数必须是数字"
print(safe_divide(10, 2)) # 5.0
print(safe_divide(10, 0)) # 错误:除数不能为 0
print(safe_divide(10, "2")) # 错误:参数必须是数字
练习 8.2:文件操作异常 编写程序读取文件,处理文件不存在、权限不足等异常。
def read_file_safe(filename):
"""安全读取文件"""
try:
with open(filename, "r", encoding="utf-8") as f:
return f.read()
except FileNotFoundError:
return f"错误:文件 {filename} 不存在"
except PermissionError:
return f"错误:没有权限读取文件 {filename}"
except Exception as e:
return f"未知错误: {e}"
content = read_file_safe("test.txt")
print(content)
练习 8.3:自定义异常
创建一个 BankAccount 类,包含取款方法。如果余额不足,抛出自定义异常 InsufficientFundsError。
class InsufficientFundsError(Exception):
"""余额不足异常"""
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
self.message = f"余额不足:当前余额 {balance},尝试取款 {amount}"
super().__init__(self.message)
class BankAccount:
def __init__(self, initial_balance=0):
self.balance = initial_balance
def deposit(self, amount):
"""存款"""
if amount < 0:
raise ValueError("存款金额不能为负数")
self.balance += amount
return self.balance
def withdraw(self, amount):
"""取款"""
if amount < 0:
raise ValueError("取款金额不能为负数")
if amount > self.balance:
raise InsufficientFundsError(self.balance, amount)
self.balance -= amount
return self.balance
# 测试
account = BankAccount(100)
try:
account.withdraw(150)
except InsufficientFundsError as e:
print(e) # 余额不足:当前余额 100,尝试取款 150
九、面向对象(类 / 继承 / 属性)
1. 定义类
class Person:
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age
def say_hello(self):
print(f"我是 {self.name}, 今年 {self.age} 岁")
p = Person("Tom", 20)
p.say_hello()
2. 继承
class Student(Person):
def __init__(self, name, age, sid):
super().__init__(name, age)
self.sid = sid
def say_hello(self):
super().say_hello()
print(f"学号是 {self.sid}")
3. 类方法 / 静态方法
class User:
count = 0 # 类属性
def __init__(self, name):
self.name = name
User.count += 1
@classmethod
def get_count(cls):
return cls.count
@staticmethod
def hello():
print("static hello")
User.hello()
print(User.get_count())
十、列表推导式 & 生成器表达式(常用“高级语法糖”)
推导式是 Python 的语法糖,可以简洁地创建列表、字典、集合。
10.1 列表推导式
基本语法:[表达式 for 变量 in 可迭代对象]
# 基本用法
nums = [1, 2, 3, 4, 5]
squares = [x * x for x in nums]
print(squares) # [1, 4, 9, 16, 25]
# 等价于
squares = []
for x in nums:
squares.append(x * x)
带条件的列表推导式:
# 只包含偶数
evens = [x for x in range(10) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
# 多个条件
result = [x for x in range(20) if x % 2 == 0 if x % 3 == 0]
print(result) # [0, 6, 12, 18]
# 等价于
result = [x for x in range(20) if x % 2 == 0 and x % 3 == 0]
嵌套循环:
# 嵌套列表推导式
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 等价于
flattened = []
for row in matrix:
for num in row:
flattened.append(num)
条件表达式(三元运算符):
# 根据条件选择值
numbers = [1, 2, 3, 4, 5]
result = ["偶数" if x % 2 == 0 else "奇数" for x in numbers]
print(result) # ['奇数', '偶数', '奇数', '偶数', '奇数']
10.2 字典推导式
基本语法:{键: 值 for 变量 in 可迭代对象}
# 创建平方字典
squares = {x: x * x for x in range(5)}
print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 从列表创建字典
names = ["Alice", "Bob", "Charlie"]
name_lengths = {name: len(name) for name in names}
print(name_lengths) # {'Alice': 5, 'Bob': 3, 'Charlie': 7}
# 带条件
even_squares = {x: x*x for x in range(10) if x % 2 == 0}
print(even_squares) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
# 反转字典
original = {"a": 1, "b": 2, "c": 3}
reversed_dict = {value: key for key, value in original.items()}
print(reversed_dict) # {1: 'a', 2: 'b', 3: 'c'}
10.3 集合推导式
基本语法:{表达式 for 变量 in 可迭代对象}
# 创建集合
squares = {x * x for x in range(5)}
print(squares) # {0, 1, 4, 9, 16}(集合,无序)
# 去重
words = ["hello", "world", "hello", "python"]
unique_lengths = {len(word) for word in words}
print(unique_lengths) # {5, 6}(去重后的长度)
10.4 生成器表达式
基本语法:(表达式 for 变量 in 可迭代对象)
生成器表达式返回生成器对象,惰性求值,节省内存。
# 生成器表达式
g = (x * x for x in range(5))
print(type(g)) # <class 'generator'>
# 使用 next() 获取下一个值
print(next(g)) # 0
print(next(g)) # 1
# 转换为列表
squares = list(g)
print(squares) # [4, 9, 16](注意:前面已经消耗了 0 和 1)
# 直接遍历
g = (x * x for x in range(5))
for square in g:
print(square) # 0, 1, 4, 9, 16
# 内存优势:处理大量数据
# 列表推导式(占用内存)
big_list = [x * x for x in range(1000000)] # 创建完整列表
# 生成器表达式(节省内存)
big_gen = (x * x for x in range(1000000)) # 不创建列表,按需生成
10.5 推导式 vs 传统循环
性能对比:
# 列表推导式通常更快
import time
# 方法 1:列表推导式
start = time.time()
result1 = [x * x for x in range(1000000)]
time1 = time.time() - start
# 方法 2:传统循环
start = time.time()
result2 = []
for x in range(1000000):
result2.append(x * x)
time2 = time.time() - start
print(f"列表推导式: {time1:.4f}秒")
print(f"传统循环: {time2:.4f}秒")
# 列表推导式通常更快
可读性:
- 简单情况:推导式更简洁
- 复杂逻辑:传统循环更清晰
10.6 练习题
练习 10.1:列表推导式 使用列表推导式完成以下任务:
- 生成 1-20 之间所有偶数的平方
- 从字符串列表
["apple", "banana", "cherry"]中提取长度大于 5 的字符串 - 将两个列表
[1, 2, 3]和[4, 5, 6]组合成元组列表
# 1. 偶数的平方
even_squares = [x * x for x in range(1, 21) if x % 2 == 0]
print(even_squares) # [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
# 2. 长度大于 5 的字符串
fruits = ["apple", "banana", "cherry"]
long_fruits = [fruit for fruit in fruits if len(fruit) > 5]
print(long_fruits) # ['banana', 'cherry']
# 3. 组合成元组列表
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = [(x, y) for x in list1 for y in list2]
print(combined) # [(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
# 或使用 zip
combined = [(x, y) for x, y in zip(list1, list2)]
print(combined) # [(1, 4), (2, 5), (3, 6)]
练习 10.2:字典推导式 使用字典推导式完成以下任务:
- 创建一个字典,键为 1-10,值为键的平方
- 从学生列表创建字典:
[("Alice", 85), ("Bob", 90), ("Charlie", 78)],键为姓名,值为成绩 - 筛选出成绩大于 80 的学生
# 1. 平方字典
squares = {x: x * x for x in range(1, 11)}
print(squares) # {1: 1, 2: 4, 3: 9, ..., 10: 100}
# 2. 学生成绩字典
students = [("Alice", 85), ("Bob", 90), ("Charlie", 78)]
scores = {name: score for name, score in students}
print(scores) # {'Alice': 85, 'Bob': 90, 'Charlie': 78}
# 3. 筛选成绩大于 80
high_scores = {name: score for name, score in students if score > 80}
print(high_scores) # {'Alice': 85, 'Bob': 90}
练习 10.3:生成器表达式 使用生成器表达式计算 1-1000 所有数字的平方和,比较内存使用。
# 使用生成器表达式(节省内存)
squares_gen = (x * x for x in range(1, 1001))
total = sum(squares_gen)
print(f"平方和: {total}") # 333833500
# 对比:列表推导式(占用更多内存)
squares_list = [x * x for x in range(1, 1001)]
total = sum(squares_list)
print(f"平方和: {total}") # 333833500
# 生成器表达式在处理大数据时更有优势
练习 10.4:综合练习 编写一个函数,接受一个字符串列表,返回一个字典,键为字符串,值为字符串中元音字母的数量。
def count_vowels_in_words(words):
"""统计每个单词中元音字母的数量"""
vowels = "aeiouAEIOU"
return {word: sum(1 for char in word if char in vowels) for word in words}
words = ["hello", "world", "python", "programming"]
result = count_vowels_in_words(words)
print(result) # {'hello': 2, 'world': 1, 'python': 1, 'programming': 3}
十一、迭代器 & 生成器函数(yield)
1. 简单生成器
def countdown(n):
while n > 0:
yield n
n -= 1
for i in countdown(3):
print(i)
yield 让函数变成生成器,可惰性输出,适合大数据流。
十二、lambda & 内置高阶函数(map/filter/sorted)
# 匿名函数
add = lambda x, y: x + y
add(2, 3)
# map
nums = [1, 2, 3]
res = list(map(lambda x: x * 2, nums))
# filter
evens = list(filter(lambda x: x % 2 == 0, nums))
# sorted + key
words = ["apple", "banana", "cat"]
sorted(words, key=len) # 按长度排
十三、装饰器(decorator)
装饰器本质是:接收函数,返回新函数。
1. 一个最简单的装饰器
def log(func):
def wrapper(*args, **kwargs):
print("调用函数:", func.__name__)
result = func(*args, **kwargs)
print("结束函数:", func.__name__)
return result
return wrapper
@log
def hello(name):
print("Hello,", name)
hello("Tom")
常见用途:日志、权限校验、缓存(如 functools.lru_cache)。
十四、上下文管理器(with) & 文件操作
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
# 自动关闭文件
自定义上下文管理器:
class MyCtx:
def __enter__(self):
print("进入")
return self
def __exit__(self, exc_type, exc, tb):
print("退出")
with MyCtx():
print("处理中")
十五、类型注解(type hints)
语法不会影响运行,只是给 IDE / 静态检查工具看的,对大型项目很重要。
from typing import List, Dict, Optional
def add(x: int, y: int) -> int:
return x + y
def get_user(name: str) -> Dict[str, str]:
return {"name": name}
def find(name: str) -> Optional[str]:
...
十六、异步编程(async / await)——进阶
适合 I/O 密集,如网络请求、爬虫、聊天服务。
import asyncio
async def fetch(url):
print("start", url)
await asyncio.sleep(1) # 模拟 I/O
print("done", url)
return f"content of {url}"
async def main():
urls = ["a.com", "b.com", "c.com"]
tasks = [fetch(u) for u in urls]
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
配合 aiohttp, httpx 等库可以做高并发爬虫、接口调用。
十七、常用内置函数 & 语法糖补充
len()、sum()、max()、min()、any()、all()enumerate():同时要索引和元素zip():并行遍历两个列表- 解包
*/**
a = [1, 2, 3]
b = [4, 5, 6]
for i, j in zip(a, b):
print(i, j)
def f(x, y, z):
print(x, y, z)
args = [1, 2, 3]
f(*args) # f(1,2,3)
kwargs = {"x": 1, "y": 2, "z": 3}
f(**kwargs)
最后给你一个“循序渐进练习路线”
你可以按这个顺序边看语法边写小脚本:
- 基础语法 + 容器:做一个“学生成绩管理”小程序(增删改查,用 list/dict)
- 函数 & 模块:把功能拆到
utils.py,写一些通用工具函数。 - 异常 & 文件 & with:做一个简单的日志系统,写入 log 文件。
- 类 & OOP:把“学生/课程”设计成类,管理对象列表。
- 推导式/装饰器/生成器:做一些数据处理小任务,比如读取 CSV → 过滤 → 统计。
- 类型注解:给所有函数加上类型标注,让 IDE/编辑器提示更智能。
- async/await(可选):写一个简单的异步爬虫或多接口并发请求 demo。 ;