PYTHON LESSON 058
考点精讲:函数组合拳与变量领地
掌握一次返回多个值、函数之间互相调用的拆题方法,彻底分清局部变量与全局变量。
00 · 学习目标
这一课要解决什么?
学完后,你应该能够
- return a, b 一次返回多个值(元组)
- 函数里调用别的函数,大任务拆小任务
- 局部变量遮蔽同名全局变量,互不影响
01 · 核心概念
多返回值、函数调用函数、局部与全局作用域的深入辨析
多返回值、函数调用函数、局部与全局作用域的深入辨析:return min(nums), max(nums) 用逗号隔开两个值,Python 会自动把它们打包成元组;调用处写 low, high = ... 两个变量一接,就各自拿到答案。选择题常考“函数返回多个值的本质”——元组。
GESP Python 4 级 · 函数的定义与调用GESP Python 4 级 · 变量作用域大量从队首删除时 list.pop(0) 是 O(n),应使用 collections.deque。
02 · 语法与规则
先记住这 3 条,再开始写程序
return a, b 一次返回多个值(元组)先准确读出这条写法的结构与作用。
函数里调用别的函数,大任务拆小任务换一组最小数据,手工推演一次结果。
局部变量遮蔽同名全局变量,互不影响再用边界值或反例确认它的适用条件。
03 · 完整实例
代码、运行结果和解释放在一起看
# 考点精讲:函数进阶与变量作用域
# 1. 一次返回多个值
def min_max(nums):
return min(nums), max(nums)
low, high = min_max([88, 95, 72, 100, 63])
print("最低分:", low, "最高分:", high)
# 2. 函数调用函数:大任务拆小
def is_leap(year):
return year % 400 == 0 or (year % 4 == 0 and year % 100 != 0)
def days_of_month(year, month):
if month == 2:
return 29 if is_leap(year) else 28
if month in [4, 6, 9, 11]:
return 30
return 31
print("2024 年 2 月有", days_of_month(2024, 2), "天")
print("2025 年 2 月有", days_of_month(2025, 2), "天")
# 3. 作用域实验:同名变量各管各
count = 100 # 全局 count
def test():
count = 1 # 局部 count,和全局的不是同一个
print("函数里的 count:", count)
test()
print("函数外的 count:", count)
# 4. 传进去的是“同一个列表”
def add_score(board, score):
board.append(score)
board = [90, 85]
add_score(board, 95)
print("积分表:", board)最低分: 63 最高分: 100 2024 年 2 月有 29 天 2025 年 2 月有 28 天 函数里的 count: 1 函数外的 count: 100 积分表: [90, 85, 95]
return a, b 返回的其实是一个元组,用两个变量接住就会自动拆包。
04 · 逐步理解
每一步只解决一个问题
- 01
return 也能一次交两件货
return min(nums), max(nums) 用逗号隔开两个值,Python 会自动把它们打包成元组;调用处写 low, high = ... 两个变量一接,就各自拿到答案。选择题常考“函数返回多个值的本质”——元组。
def min_max(nums): return min(nums), max(nums) - 02
大任务拆成小函数
算“某年某月有几天”,最难的是 2 月要看闰年。把“是不是闰年”单独写成 is_leap,days_of_month 里直接调用它——每个函数只干一件事,合起来解决大问题。
def days_of_month(year, month): if month == 2: return 29 if is_leap(year) else 28 - 03
闰年判断的逻辑链
闰年规则:能被 400 整除,或者能被 4 整除但不能被 100 整除。翻译成代码就是 year % 400 == 0 or (year % 4 == 0 and year % 100 != 0),括号保证先算 and 再算 or。
return year % 400 == 0 or (year % 4 == 0 and year % 100 != 0) - 04
同名变量的“遮蔽”现象
函数里写 count = 1,并没有改动全局的 count,而是在函数内部新造了一个同名局部变量,把全局的暂时“遮住”了。所以函数里打印 1,函数外打印的还是 100。
count = 100 def test(): count = 1 print(count) - 05
读程序题的作用域口诀
考级读程序题最爱考作用域。口诀:函数里“赋值”就是造局部变量(除非用 global 声明);只是“读取”则会向外找全局变量。拿笔在草稿纸上给每个变量标出领地,就不容易错。
- 06
列表传参为什么例外
add_score 里 append 居然改动了外面的 board?因为传参传的是“同一个列表”本身,不是复制品。数字、字符串不可变所以没事,列表、字典可变就会这样——这是 4 级必考点。
def add_score(board, score): board.append(score)
05 · 练习与检验
自己写出来,才算真正学会
- 1运行程序,看 min_max 一次交出两个答案
- 2用 days_of_month 查一查你出生的月份
- 3解释为什么函数外的 count 还是 100
- 4给 add_score 改成返回新列表的版本
06 · 完整知识
继续理解定义、规则和适用边界
第一次学习先完成上面的六个步骤;需要查定义、核对规则、分析误区或理解“为什么”时,再展开对应知识章。
核心数据结构列表、元组、字典与集合按顺序、可变性、唯一性和查找需求选择容器,并掌握遍历、推导式、排序与复制。+
正式定义
容器保存多个对象。list 是可变有序序列,tuple 是不可变有序序列,dict 保存唯一键到值的映射,set 保存无序且不重复的可哈希对象。
必须掌握
- list 支持下标、切片、append、extend、insert、pop、remove 与 sort;多数修改方法返回 None。
- tuple 的逗号比括号更关键,单元素元组必须写成 (value,)。
- dict 保持插入顺序;键必须可哈希且唯一,get 可提供缺省值,items 同时遍历键和值。
- set 用于去重与集合运算:| 并、& 交、- 差、^ 对称差;空集合必须写 set()。
- enumerate 同时给出序号和值,zip 并行遍历多个可迭代对象,默认在最短输入处停止。
- 浅复制只复制最外层容器;嵌套可变对象仍可能共享。
CORE CONTAINER METHODS
四类核心容器方法完整速查
修改型方法多数返回 None;表中“浅复制”不会递归复制内部可变对象。
| 类型 | 方法 | 核心作用 |
|---|---|---|
list | append(x) | 末尾加入一个对象 |
list | extend(iterable) | 末尾加入可迭代对象的每一项 |
list | insert(i, x) | 在下标 i 前插入 |
list | remove(x) | 删除第一个等于 x 的元素,不存在时报错 |
list | pop([i]) | 删除并返回指定项,默认末项 |
list | clear() | 删除全部元素 |
list | index(x[, start[, stop]]) | 返回第一个匹配下标 |
list | count(x) | 统计等于 x 的元素数 |
list | sort(*, key=None, reverse=False) | 稳定地原地排序 |
list | reverse() | 原地逆序 |
list | copy() | 浅复制列表 |
tuple | count(x) | 统计元素次数 |
tuple | index(x[, start[, stop]]) | 返回第一个匹配下标 |
dict | clear() | 删除全部键值对 |
dict | copy() | 浅复制字典 |
dict | fromkeys(iterable[, value]) | 用一组键创建新字典 |
dict | get(key[, default]) | 安全取值,缺键返回默认值 |
dict | items() | 键值对动态视图 |
dict | keys() | 键动态视图 |
dict | pop(key[, default]) | 删除键并返回值 |
dict | popitem() | 删除并返回最后加入的键值对 |
dict | setdefault(key[, default]) | 缺键时写入默认值并返回 |
dict | update(other) | 用映射或键值对更新 |
dict | values() | 值动态视图 |
set | add(x) | 加入一个元素 |
set | clear() | 删除全部元素 |
set | copy() | 浅复制集合 |
set | discard(x) | 删除元素,不存在也不报错 |
set | remove(x) | 删除元素,不存在时报错 |
set | pop() | 删除并返回任意元素 |
set | union(*others) | 返回并集 |
set | update(*others) | 用并集原地更新 |
set | intersection(*others) | 返回交集 |
set | intersection_update(*others) | 用交集原地更新 |
set | difference(*others) | 返回差集 |
set | difference_update(*others) | 用差集原地更新 |
set | symmetric_difference(other) | 返回对称差 |
set | symmetric_difference_update(other) | 用对称差原地更新 |
set | issubset(other) | 是否为子集 |
set | issuperset(other) | 是否为超集 |
set | isdisjoint(other) | 是否没有共同元素 |
常见误区
- 把 list.sort() 的返回值赋回列表
- 遍历 dict 时同时改变其大小
- 用可变 list 当字典键
- 把 set 当成有固定顺序的序列
适用边界
- 大量从队首删除时 list.pop(0) 是 O(n),应使用 collections.deque。
- 需要有序映射的特殊操作、计数或默认值时可查阅 collections,但先理解基本 dict。
程序组织函数、参数、返回值与作用域用明确的输入、输出和职责拆分程序,理解参数绑定、作用域、递归与可变对象。+
正式定义
函数把一段可复用行为绑定到名字。调用时实参按规则绑定到形参,函数执行后用 return 交回结果;没有显式 return 时返回 None。名字解析遵循局部、闭包、全局、内置的 LEGB 顺序。
必须掌握
- 位置参数先于关键字参数;默认值在 def 执行时创建一次,不应直接使用可变容器作默认值。
- return 立即结束当前函数;return a, b 实际返回一个元组。
- 函数内赋值默认创建局部变量;global 声明模块级名字,nonlocal 声明最近外层函数名字。
- 传参传递的是对象引用;函数是否影响调用方取决于对象是否可变以及函数是否原地修改。
- 递归必须有可到达的终止条件,并要考虑调用深度、重复子问题和栈空间。
- 纯函数更容易测试;把输入输出、计算逻辑和全局状态分开能显著减少错误。
常见误区
- 可变默认参数在多次调用间共享
- 忘记 return 导致得到 None
- 局部变量遮蔽全局同名变量
- 递归没有缩小问题规模
适用边界
- lambda 只能包含一个表达式,适合短小的排序键,不适合塞入复杂业务逻辑。
- 装饰器、生成器和闭包属于函数模型的进阶应用,应在基本参数与作用域稳定后学习。
Python 基础运算符、表达式与优先级完整区分算术、比较、逻辑、成员、身份和位运算,并用优先级表消除歧义。+
正式定义
表达式求值得到一个值。运算符规定如何组合操作数;当一个表达式含多个运算符时,优先级和结合方向决定求值顺序,括号可以明确改变顺序。
必须掌握
- / 总是得到浮点结果;// 是向负无穷方向取整的整除;% 与 // 满足 a == (a // b) * b + a % b。
- 比较可以链式书写,如 0 <= x < 10;and/or 会短路并返回最后求值的操作数,不一定返回 bool。
- == 比较值是否相等,is 比较是否为同一个对象;判断 None 应写 is None。
- in/not in 做成员测试;对 dict 测试的是键。
- 位运算作用于整数的二进制位;负整数按无限长二进制补码语义理解。
- 复杂表达式即使能靠优先级正确运行,也应使用括号表达意图。
常见误区
- 把 // 当成简单截断
- 用 is 比较数字或字符串的值
- 忘记 and 的优先级高于 or
- 连续位移、比较和逻辑运算却不加括号
适用边界
- 浮点数比较受二进制表示误差影响,需要按问题选择容差。
- 运算符可由自定义类重载,因此相同符号对不同类型可能有不同语义。
编码与文本字符串、转义、切片与格式化从不可变字符序列到检索、拆分、拼接、格式化和常用判断方法。+
正式定义
str 是不可变的 Unicode 字符序列。下标访问单个字符,切片生成新字符串;任何看似“修改字符串”的方法都会返回新对象。
必须掌握
- 下标从 0 开始,负下标从末尾开始;切片 s[start:stop:step] 不包含 stop,step 不能为 0。
- 转义序列用于在字面量中表示换行、制表、引号、反斜杠或码点;原始字符串仍有末尾反斜杠限制。
- find 找不到返回 -1,index 找不到抛 ValueError;count 统计不重叠出现次数。
- split 把字符串拆成列表,join 用一个字符串连接可迭代对象中的字符串,strip 只删除两端字符。
- f-string 的格式说明可控制宽度、对齐、精度、进制和百分比;格式化不改变原值。
- isalpha/isdigit 等按 Unicode 定义,不只识别英文字母和 ASCII 数字。
常见误区
- 尝试 s[0] = 'A' 原地修改字符串
- 把 strip('ab') 误解为删除完整子串 'ab'
- find 返回 -1 后直接拿去当有效下标
- 把字节长度与字符长度混为一谈
适用边界
- 正则表达式不在低等级字符串必修范围,但复杂模式匹配时应使用 re,而不是堆叠大量 split/find。
- 面向用户的字符计数还可能涉及组合字符和字素簇,len 统计的是 Unicode 码点序列长度。
完成检查