引言
今天我们来深入探讨Python的控制流和数据结构。这些知识是编程的骨架,掌握好它们,你就能写出更强大、更优雅的代码!
文章目录
一、条件判断进阶:不只是if-else
条件判断多使用if进行判定。在Python 3.10中引入了match语句,让复杂的条件判断变得简洁优雅。
match语句接受一个表达式并把它的值与一个或多个 case 块给出的一系列模式进行比较。类似于C、Java 或 JavaScript中的 switch-case语句。
# 传统方式:多层if-elif
def handle_http_status(code):
if code == 200:
return "成功"
elif code == 404:
return "未找到"
elif code == 500:
return "服务器错误"
else:
return "未知状态"
# match函数
def http_error(status):
match status: #开启判断
case 400:
return "Bad request"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _: #通配符
return "Something's wrong with the internet"
你可以用 | (“或”)将多个字面值组合到一个模式中。
case 401 | 403 | 404:
return "Not allowed"
其他更高级的匹配模式
# 更高级的模式匹配
def process_data(data):
match data:
case []:
print("空列表")
case [x]:
print(f"单元素列表: {x}")
case [x, y, *rest]:
print(f"多元素列表: 前两个是{x}, {y}, 剩余{len(rest)}个")
case {"status": "success", "data": result}:
print(f"成功获取数据: {result}")
case {"status": "error", "message": msg}:
print(f"错误: {msg}")
case _:
print("未知数据格式")
二、函数定义:让你的代码更模块化
定义函数使用关键字def,后跟函数名与括号内的形参列表。函数定义支持可变数量的参数。
2.1 默认值参数
为参数指定默认值是非常有用的方式。调用函数时,可以使用比定义时更少的参数。
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
reply = input(prompt)
if reply in {'y', 'ye', 'yes'}:
return True
if reply in {'n', 'no', 'nop', 'nope'}:
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
ask_ok函数可以用以下方式调用:
1)只给出必选实参:ask_ok(‘Do you really want to quit?’)
2)给出一个可选实参:ask_ok(‘OK to overwrite the file?’, 2)
3)给出所有实参:ask_ok(‘OK to overwrite the file?’, 2, ‘Come on, only yes or no!’)
2.2 关键字参数
key=value形式的关键字参数,也可以用于调用函数。
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
pass
# 函数调用
parrot(1000) # 1 个位置参数
parrot(voltage=1000) # 1 个关键字参数
parrot(voltage=1000000, action='VOOOOOM') # 2 个关键字参数
parrot(action='VOOOOOM', voltage=1000000) # 2 个关键字参数
parrot('a million', 'bereft of life', 'jump') # 3 个位置参数
parrot('a thousand', state='pushing up the daisies') # 1 个位置参数,1 个关键字参数
2.3 特殊参数
一般默认情况下,参数可以按位置或显式关键字传递给 Python 函数。函数综合定义如下:其中/ 和 * 是可选的。
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| 位置或关键字 |
| - 仅限关键字
-- 仅限位置
函数调用要求独立的位置参数,但实参在列表或元组里时,要执行相反的操作。
不独立的参数,则要在调用函数时,用 *操作符 把实参从列表或元组解包出来。
字典可以用 ** 操作符 传递关键字参数。
# *args:接收任意数量的位置参数
def sum_numbers(*args):
"""计算任意数量数字的和"""
print(f"参数类型: {type(args)}") # tuple
return sum(args)
print(sum_numbers(1, 2, 3, 4, 5)) # 15
# **kwargs:接收任意数量的关键字参数
def create_person(**kwargs):
"""创建个人信息字典"""
person = {
"name": kwargs.get("name", "匿名"),
"age": kwargs.get("age", 18),
"city": kwargs.get("city", "未知")
}
# 添加其他所有参数
person.update(kwargs)
return person
print(create_person(name="小明", age=25, job="工程师", city="北京"))
# {'name': '小明', 'age': 25, 'city': '北京', 'job': '工程师'}
2.4 闭包和装饰器:函数的高级用法
闭包:一个能记住并访问其创建时所在作用域(即便该作用域已经执行完毕)的函数。
其关键点在于函数的嵌套使用,内部函数引用外部函数的变量,外部函数可以返回内部函数本身,它允许你保存状态。
# 闭包:函数记住并访问创建时的作用域
def make_multiplier(factor):
"""创建一个乘法器函数"""
def multiplier(x):
return x * factor
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
装饰器:一个用于修改或增强其他函数功能的特殊函数,而不改变被装饰函数的源代码和调用方式。
其目的是不修改原函数代码,为其添加新功能。方法是使用 @decorator_name 的语法糖,让代码非常简洁清晰。其底层实现依赖于闭包,因为它返回的包装函数需要“记住”传入的那个原始函数
# 装饰器:修改函数的行为
def timer(func):
"""计算函数执行时间的装饰器"""
def wrapper(*args, **kwargs):
import time
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():
"""模拟耗时函数"""
import time
time.sleep(1)
return "完成"
print(slow_function()) # 输出执行时间并返回"完成"
三、range函数:不只是生成数字
range函数是Python中非常高效的工具,多用于循环当中。
# 基本用法
for i in range(5):
print(i, end=" ") # 0 1 2 3 4
# 指定起始和结束
for i in range(2, 6):
print(i, end=" ") # 2 3 4 5
# 指定步长
for i in range(0, 10, 2):
print(i, end=" ") # 0 2 4 6 8
# 逆序
for i in range(5, 0, -1):
print(i, end=" ") # 5 4 3 2 1
# 与enumerate结合使用
fruits = ["苹果", "香蕉", "橙子"]
for i, fruit in enumerate(fruits, start=1):
print(f"{i}. {fruit}")
#1. 苹果
#2. 香蕉
#3. 橙子
# 用于创建列表
numbers = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
even_numbers = list(range(0, 20, 2)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
四、数据结构详解:Python的"瑞士军刀"
4.1 列表list:最灵活的数据结构
定义:列表一种可变的、有序的数据结构,用于存储一组元素,这些元素可以是不同类型的对象,并且可以通过索引访问。列表使用方括号[]定义,元素之间用逗号分隔。
定义格式:[元素1, 元素2, 元素3, ...]
列表基本操作包括:创建、增删改查。
创建为直接赋值式创建和推导式创建。
增加包括尾部追加,指定位置追加以及批量扩展;
删除包括尾部移除,指定元素移除以及指定位置移除;
修改直接采用赋值式修改;
查询直接通过索引即可。
# 列表创建 & 赋值/修改
fruits = ["苹果", "香蕉", "橙子"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]
# 列表推导式创建(超级实用!)
squares = [x^2 for x in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
even_squares = [x^2 for x in range(10) if x % 2 == 0] # 只计算偶数的平方
matrix = [[i*j for j in range(3)] for i in range(3)] # 二维列表
# 列表操作 - 添加
fruits.append("葡萄") # 添加元素
fruits.insert(1, "草莓") # 在指定位置插入
fruits.extend(["西瓜", "菠萝"]) # 扩展列表
# 列表操作 - 移除
removed = fruits.pop() # 移除并返回最后一个元素
fruits.remove("香蕉") # 移除指定元素
del fruits[2] # 移除指定位置元素
# 列表操作 - 查询
print(fruits[0]) #注意索引越界会提示 list index out of range
索引:通过列表名加中括号内的数字进行索引,正数为正向获取,负数为逆向索引。
切片:通过start:end形式获取子列表,含start不含end。::step为布长获取,::-1为反转列表。
# 列表切片(非常重要!)
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(numbers[2:5]) # [2, 3, 4] 索引2到5(不含5)
print(numbers[:3]) # [0, 1, 2] 从开头到索引3
print(numbers[5:]) # [5, 6, 7, 8, 9] 从索引5到结尾
print(numbers[::2]) # [0, 2, 4, 6, 8] 步长为2
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 反转列表
4.2 元组tuple:不可变的列表
定义:不可变的列表,使用括号()定义,元素之间用逗号分隔。
元组包括索引和切片,仅不支持修改。
常用于不可外界修改的用户数据。
而括号在运算中代表优先级,因此特制定元组时,元素后面添加逗号。
# 创建元组
point = (10, 20)
colors = ("红", "绿", "蓝")
single_element = (42,) # 注意逗号!(42)会被认为是整数42
# 元组解包
x, y = point # x=10, y=20
first, *rest = colors # first="红", rest=["绿", "蓝"]
# 元组与列表转换
numbers_list = [1, 2, 3]
numbers_tuple = tuple(numbers_list) # (1, 2, 3)
tuple_to_list = list(numbers_tuple) # [1, 2, 3]
# !!! 元组内对象元素可扩展
t = (1, 2, 3, ['张三', '男', 28])
t[3].append("山东") #t会变成(1, 2, 3, ['张三', '男', 28, '山东'])
4.3 集合set:去重和集合运算
集合是一种无序的、可变的、不重复元素的数据结构,用于存储唯一的元素集合。集合使用花括号{}或set()函数定义,元素之间用逗号分隔。
# 定义格式:
- 非空集合:{元素1, 元素2, 元素3, ...}
- 空集合:set() (注意:{} 是空字典)
Python中集合Set进行存储时,需要将元素数据进行哈希处理,进而存储。若存储对象不可哈希,则会出错。
可哈希对象:字符串str、元组tuple、文本、数字number、布尔值等不可变的数据类型
不可哈希对象:列表List、字典、集合Set等可变数据类型
常见的创建、运算见示例,其主常见作用快速去重。
# 创建集合
unique_numbers = {1, 2, 3, 3, 2, 1} # {1, 2, 3},自动去重
empty_set = set() # 空集合,注意不是{}(这是空字典)
# 添加元素
s = {1, 2, 3}
s.add(4) # → {1, 2, 3, 4}
s.update([5, 6]) # → {1, 2, 3, 4, 5, 6}
# 删除元素
s.remove(3) # 删除存在的元素
s.discard(10) # 删除不存在的元素不报错
# 集合运算
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
print(A | B) # 并集: {1, 2, 3, 4, 5, 6, 7, 8}
print(A & B) # 交集: {4, 5}
print(A - B) # 差集: {1, 2, 3}
print(A ^ B) # 对称差集: {1, 2, 3, 6, 7, 8}
# 集合推导式
squares_set = {x**2 for x in range(10)} # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
# 实际应用:快速去重
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
unique_words = set(words) # {"apple", "banana", "orange"}
4.4 字典dict:键值对的威力
字典是一种可变的、无序的键值对集合,用于存储映射关系。
字典使用花括号{}定义,每个元素由键和值组成,格式为键: 值,元素之间用逗号分隔。
每个元素包含一个键(key)和一个值(value),键必须是不可变类型且唯一。
注:Python 3.7+更改为有序
定义格式:{键1: 值1, 键2: 值2, 键3: 值3, ...}
例如:
- 空字典:{} 或 dict()
- 简单字典:{'name': '张三', 'age': 25, 'city': '北京'}
- 嵌套字典:{'person': {'name': '李四', 'age': 30}, 'scores': [85, 90, 88]}
- 混合类型:{1: 'one', 'two': 2, (1,2): 'tuple_key', 3.14: 'pi'}
- 重复键(后者覆盖前者):{'a': 1, 'a': 2} → {'a': 2}
使用示例
# 创建字典
student = {"name": "小明", "age": 20, "major": "计算机"}
grades = dict([("数学", 90), ("英语", 85), ("物理", 88)])
grades.setdefault("综合", 80) #设置默认值是综合80,如果已经设置过则不生效
# 访问和修改
print(student["name"]) # 小明
student["age"] = 21 # 修改值
student["grade"] = "大二" # 添加新键
# print(student["height"]) # KeyError! 键不存在时抛出异常
print(student.get("height", 175)) # 安全访问,返回默认值175
# 字典方法
keys = student.keys() # 所有键
values = student.values() # 所有值
items = student.items() # 所有键值对
# 循环访问
for key, value in student.items():
print(f"{key}: {value}")
# 字典推导式
squares_dict = {x: x**2 for x in range(5)} # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 合并字典(Python 3.9+)
dict1 = {"a": 1, "b": 2}
dict2 = {"b": 3, "c": 4}
merged = dict1 | dict2 # {"a": 1, "b": 3, "c": 4},后面的覆盖前面的
五、循环技巧:让代码更高效
5.1 enumerate
enumerate是 Python 的内置函数,用于给可迭代对象(如列表、元组、字符串等)添加序号(索引),返回一个包含索引和元素的枚举对象。
基本语法:enumerate(iterable, start=0)
iterable:要遍历的对象(列表、元组、字符串等)
start:索引起始值,默认为 0
示例:
fruits = ["苹果", "香蕉", "橙子"]
for index, fruit in enumerate(fruits, start=1):
print(f"{index}. {fruit}")
# 1. 苹果
# 2. 香蕉
# 3. 橙子
5.2 zip
zip 是 Python 的内置函数,用于将多个可迭代对象"打包"成一个元组序列,按位置对应组合元素。
基本语法:zip(iterable1, iterable2, ...)
iterable1:可迭代的对象(列表、元组、字符串等)。
示例:
names = ["小明", "小红", "小刚"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f"{name}: {score}分")
5.3 reversed:反向迭代
reversed 是 Python 的内置函数,用于返回一个序列的反向迭代器,将元素顺序反转。
基本语法:reversed(sequence)
示例:
for i in reversed(range(5)):
print(i, end=" ") # 4 3 2 1 0
#反转字符串
s = "hello"
''.join(reversed(s)) # → "olleh"
# 反转元组
t = (1, 2, 3, 4)
tuple(reversed(t)) # → (4, 3, 2, 1)
5.4 else子句
else 在 Python 中有多种用法,不仅限于 if-else 条件判断。
for-else(循环结束后)
当循环正常完成(没有被 break 中断)时执行。
numbers = [2, 4, 6, 8, 10]
for num in numbers:
if num % 2 != 0: # 找到奇数
print("找到奇数")
break
else:
print("全是偶数") # 循环正常结束才会执行
while-else(循环结束后)
与 for-else 类似,循环正常结束执行。
count = 0
while count < 5:
print(count)
count += 1
else:
print("循环完成") # 当while条件为假时执行
5.5 其他
1)列表推导式替代简单循环
# 传统方式
squares = []
for i in range(10):
squares.append(i**2)
# 推导式方式(更简洁高效)
squares = [i**2 for i in range(10)]
2)生成器表达式处理大数据
# 列表推导式(立即计算,占用内存)
big_list = [x**2 for x in range(1000000)] # 占用大量内存
# 生成器表达式(惰性计算,节省内存)
big_generator = (x**2 for x in range(1000000)) # 几乎不占内存
for value in big_generator:
# 处理每个值
pass
六、高频面试题解析
问题1:Python中的可变对象和不可变对象有什么区别
参考答案:
1)可变对象可以直接修改,多个变量指向同一对象时会相互影响
2)不可变对象创建后不能修改,每次"修改"都会创建新对象
3)函数参数传递时要注意这一点,特别是默认参数
# 可变对象(mutable):列表、字典、集合
list1 = [1, 2, 3]
list2 = list1
list2.append(4)
print(list1) # [1, 2, 3, 4] # list1也被修改了!
# 不可变对象(immutable):数字、字符串、元组
str1 = "hello"
str2 = str1
str2 = str2 + " world"
print(str1) # "hello" # str1没有被修改
print(str2) # hello world
# str2的值更改了,其id也发生了变化,不可变对象上任何"修改"操作实际上都会创建新的对象
问题2: 写一个装饰器,记录函数的执行时间
import time
import functools
def timer(func):
"""记录函数执行时间的装饰器"""
@functools.wraps(func) # 保留原函数的元信息
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
print(f"{func.__name__} 执行时间: {end_time - start_time:.6f}秒")
return result
return wrapper
@timer
def slow_function(n):
"""模拟耗时函数"""
time.sleep(n)
return f"休眠了{n}秒"
# 使用
print(slow_function(1)) # 会输出执行时间
print(slow_function.__name__) # 输出'slow_function'而不是'wrapper'
七、总结
学习要点回顾
条件判断:match语句让复杂条件更清晰
函数定义:args和*kwargs处理可变参数,装饰器增强函数功能
range函数:高效生成数字序列
数据结构:
列表:灵活可变,支持切片和推导式
元组:不可变,适合作为字典键或函数返回值
集合:去重和集合运算
字典:高效的键值对存储
编程建议
✅ 推荐做法
· 使用列表推导式替代简单循环
· 善用enumerate和zip简化代码
· 使用get()方法安全访问字典
· 用集合进行快速去重和成员检查
❌ 避免做法
· 不要在循环中修改正在迭代的集合
· 避免使用可变对象作为函数默认参数
· 不要用"+"大量拼接字符串(用join替代)
相关实战小游戏见代码篇:简单文字冒险游戏
下一期预告
下一篇我们将深入学习Python模块和输入输出,包括:如何创建和使用自己的模块、文件读写的高级技巧、JSON、CSV等格式的处理、异常处理的最佳实践、标准输入输出的高级用法。
掌握这些知识后,你就能编写更加实用、健壮的Python程序了!
如果觉得有帮助,请关注+点赞+收藏,这是对我最大的鼓励! 如有问题,请评论区留言

被折叠的 条评论
为什么被折叠?



