Python 核心知识点总结:变量、函数与参数传递

基于我们之前的讨论,这里将 Python 中关于变量本质、函数机制、列表推导式以及函数参数传递的核心知识点整理成一份系统的 Markdown 文档,方便你复习和查阅。


一、 变量与内存的本质(“标签与房间”模型)

理解 Python 变量的关键在于区分变量名和内存地址。

  • 内存(房间):计算机中真正存储数据的地方。
  • 内存地址(房间编号):每个内存空间都有唯一的编号(可以使用 id() 查看)。
  • 变量名(标签):变量名本身不存储数据,它仅仅是贴在“房间门”上的一个标签。它指向了内存地址。
  • 变量值(房间里的内容):实际存储在内存中的数据。

核心结论:
在 Python 中,一切皆对象。函数、列表、数字、字符串都是对象。赋值操作(=)的本质,就是把“标签”贴在“房间”上。


二、 函数的本质与内存机制

结合“标签与房间”模型,函数在 Python 中的运作方式如下:

  1. **定义函数 (def func():)**:
    • Python 会在内存中开辟一块专属的“房间”。
    • 这个房间里装的不是普通数据,而是一段可执行的代码块(函数体)。
    • 函数名 func 就是贴在门口的第一张标签。
  2. **函数别名 (foo = func)**:
    • 这不是复制代码。它只是拿了一张新标签 foo,贴在了同一个房间的门上。
    • 此时,func 和 foo 指向完全相同的内存地址。执行 foo() 和 func() 效果完全一致。
  3. **调用函数 (func())**:
    • 加括号 () 是“执行”的标志。
    • 它的含义是:顺着标签找到内存地址(房间),取出里面的代码块并自动运行。
    • 不加括号(如 foo = func)传递的是“房间号(标签)”;加括号(如 foo = func())传递的是“房间里代码运行后的结果”。

三、 列表推导式与嵌套还原

列表推导式(List Comprehension)是 Python 中非常优雅的语法,但多层嵌套容易让人晕头转向。

1. 基础结构

[表达式 for 变量 in 可迭代对象 if 条件]

2. 嵌套推导式的执行顺序

原式:[变量 for 变量 in [变量 for 变量 in 可迭代类型] if 表达式]

还原原则:从内到外,先执行内层,将内层的结果作为外层的数据源。

还原为普通 for 循环的步骤:

1
2
3
4
5
6
7
8
9
10
# 第一步:先执行内层推导式,生成一个临时列表
临时列表 = []
for 变量 in 可迭代类型:
临时列表.append(变量)

# 第二步:执行外层推导式和条件判断
最终结果 = []
for 变量 in 临时列表: # 遍历内层生成的结果
if 表达式: # 对应 if 条件
最终结果.append(变量)

四、 函数参数传递 (*args 和 **kwargs)

在 Python 中,函数定义时的参数顺序有严格规定:**位置参数 -> 默认参数 -> *args -> **kwargs**。

1. 星号 * 在函数调用中的作用(解包)

在调用函数时,* 被称为解包操作符。

  • 如果 num_list = [1, 2, 3]:
    • print(num_list) 输出 [1, 2, 3](打印整个列表对象)。
    • print(*num_list) 输出 1 2 3(把列表拆开,等同于 print(1, 2, 3),默认用空格分隔)。

2. *args 和 **kwargs 的接收机制

  • *args (可变位置参数):收集所有多余的、未匹配的“位置参数”,并将它们打包成一个**元组 (Tuple)**。
  • **kwargs (可变关键字参数):收集所有多余的、未匹配的“关键字参数”,并将它们打包成一个**字典 (Dictionary)**。

3. 经典案例分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def add(x, y, *args, **kwargs):
print(x, y)
print(args)
print(kwargs)

# 调用 1:全部使用关键字参数
add(x=1, y=2, z=3, u=5)
# 输出:
# 1 2
# () <-- 没有多余的位置参数,args 为空元组
# {'z': 3, 'u': 5} <-- z 和 u 被 kwargs 收集为字典

# 调用 2:混合使用位置和关键字参数
add(1, 2, 3, 4, z=5)
# 输出:
# 1 2
# (3, 4) <-- 多余的位置参数 3, 4 被 args 收集为元组
# {'z': 5} <-- 关键字参数 z=5 被 kwargs 收集为字典

五、 总结与避坑指南

  1. 传参避坑:在调用函数时,传递的是函数名(标签)还是函数调用结果(函数名()),有着本质区别。前者传递的是功能,后者传递的是返回值(如果没有 return 则为 None)。
  2. 内存回收:当一个对象(房间)没有任何标签(变量名)指向它时,Python 的垃圾回收机制就会把这个房间清理掉。
  3. 参数顺序:定义函数时,务必遵循 普通参数 -> *args -> 默认参数 -> **kwargs 的顺序(注:默认参数通常放在 *args 之前,但如果默认参数在 *args 之后,则调用时必须使用关键字传参,否则容易报错。严格来说推荐:位置参数, 默认参数, *args, **kwargs)。