Python 入门必吃透:函数、列表与元组核心用法
这三个知识点是 Python 初学者最容易混淆、但使用频率最高的三大基础。
把它们真正吃透,能让你写出更清晰、更 Pythonic 的代码。
下面按“理解 → 核心用法 → 常见陷阱 → 最佳实践”的结构,帮你系统梳理。
一、函数(Function)—— Python 的“第一等公民”
1. 最核心的定义方式对比
# 方式1:普通函数(最常用)
def add(a, b):
return a + b
# 方式2:lambda(匿名函数,单表达式)
add = lambda a, b: a + b
# 方式3:带默认值的函数(非常常用)
def greet(name="客人", greeting="你好"):
print(f"{greeting},{name}!")
# 方式4:位置参数 + 关键字参数 + 可变参数(*args, **kwargs)
def func(a, b, *args, c=10, **kwargs):
print(a, b) # 必填位置参数
print(args) # 多余的位置参数 → 元组
print(c) # 带默认值的关键字参数
print(kwargs) # 多余的关键字参数 → 字典
2. 参数传递的核心规则(最容易错)
| 参数类型 | 传递方式 | 修改函数内会影响外部吗? | 典型例子 |
|---|---|---|---|
| 不可变类型 | 值传递 | 不会 | int、float、str、tuple、bool |
| 可变类型 | 引用传递 | 会 | list、dict、set、自定义类实例 |
# 经典陷阱
def append_to_list(lst=[]): # !!!默认值只在函数定义时创建一次
lst.append(1)
return lst
print(append_to_list()) # [1]
print(append_to_list()) # [1, 1] ← 不是新列表!
print(append_to_list()) # [1, 1, 1]
正确写法:
def append_to_list(lst=None):
if lst is None:
lst = []
lst.append(1)
return lst
3. 函数常用高阶用法(入门后期必会)
- 函数作为参数(map、filter、sorted)
names = ["alice", "BOB", "Charlie"]
upper_names = list(map(str.upper, names))
print(upper_names) # ['ALICE', 'BOB', 'CHARLIE']
sorted_names = sorted(names, key=str.lower)
print(sorted_names) # ['alice', 'BOB', 'Charlie']
- 闭包函数(非常重要)
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier
times3 = make_multiplier(3)
print(times3(10)) # 30
- 装饰器(初阶写法)
def log(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__},参数:{args}, {kwargs}")
return func(*args, **kwargs)
return wrapper
@log
def add(a, b):
return a + b
add(5, 7)
# 输出:调用 add,参数:(5, 7), {}
二、列表(list)—— 最灵活、最常用的序列类型
1. 核心操作速查表
| 操作 | 写法 | 时间复杂度 | 修改原列表? | 说明 |
|---|---|---|---|---|
| 访问/修改 | lst[3] = 100 | O(1) | 是 | 索引访问 |
| 追加 | lst.append(x) | O(1) 均摊 | 是 | 最常用追加方式 |
| 插入 | lst.insert(0, x) | O(n) | 是 | 插入到指定位置 |
| 删除元素 | lst.pop() / lst.pop(0) | O(1) / O(n) | 是 | 尾删快,头删慢 |
| 删除指定值 | lst.remove(x) | O(n) | 是 | 删除第一个匹配的 x |
| 切片 | lst[1:5:2] | O(k) | 否(返回新) | 切片产生新列表 |
| 列表推导式 | [x*2 for x in lst if x>0] | — | 否 | 最 Pythonic 的创建方式 |
| 扩展列表 | lst.extend([7,8]) 或 lst += [7,8] | O(k) | 是 | 比 append 多个元素效率更高 |
2. 列表常见陷阱
# 陷阱1:乘法创建列表(浅拷贝)
a = [[]] * 3 # 错误!
a[0].append(1)
print(a) # [[1], [1], [1]] ← 三个引用同一个列表
# 正确写法
a = [[] for _ in range(3)]
a[0].append(1)
print(a) # [[1], [], []]
# 陷阱2:切片赋值会改变长度
lst = [1, 2, 3, 4]
lst[1:3] = [99] # 可以把一段替换成不同长度
print(lst) # [1, 99, 4]
3. 列表推导式高级写法(强烈推荐掌握)
# 普通循环 → 推导式
squares = [x**2 for x in range(10) if x % 2 == 0]
# 嵌套推导式(扁平化二维列表)
matrix = [[1,2,3], [4,5,6], [7,8,9]]
flat = [num for row in matrix for num in row]
# 字典推导式(常与列表一起用)
{str(x): x**2 for x in range(5)}
三、元组(tuple)—— 不可变、有序、轻量
1. 元组 vs 列表核心对比
| 特性 | tuple(元组) | list(列表) |
|---|---|---|
| 是否可变 | 不可变 | 可变 |
| 性能 | 更快、更省内存 | 稍慢 |
| 作为字典 key | 可以 | 不可以 |
| 解包 | 支持 | 支持 |
| 单元素写法 | (5,) | [5] |
| 典型用途 | 返回多个值、作为记录、key | 动态数据、需要修改的序列 |
2. 元组最强大的特性:解包
# 经典多返回值
def get_person():
return "Alice", 25, "Beijing"
name, age, city = get_person() # 自动解包
print(name, age, city) # Alice 25 Beijing
# 交换变量(最 Pythonic 写法)
a, b = 1, 2
a, b = b, a # 无需临时变量
# 部分解包 + 收集
first, *middle, last = [1, 2, 3, 4, 5]
print(first, middle, last) # 1 [2, 3, 4] 5
3. 元组的“伪可变”陷阱
t = (1, 2, [3, 4])
t[2].append(5) # 可以!因为列表是可变的
print(t) # (1, 2, [3, 4, 5])
# 但下面会报错
t[2] = [7, 8] # TypeError: 'tuple' object does not support item assignment
结论:元组本身不可变,但它包含的可变对象内容仍然可以改变。
四、总结:函数 + 列表 + 元组 的使用原则(强烈建议背下来)
- 函数参数默认值:永远不要用可变对象(如 []、{})做默认值
- 需要修改 → 用 list
- 不需要修改、想做 key、想返回多个值 → 用 tuple
- 创建小列表 → 优先列表推导式
[x for x in ...] - 频繁追加 → 用
append()或extend() - 需要有序且不可变 → 用 tuple(尤其是作为字典的 key)
- 解包 是 Python 最优雅的特性之一,多用!
五、快速练习题(建议自己写一写)
- 写一个函数,返回一个列表中所有偶数的平方(用推导式)
- 实现一个函数,把任意数量的参数收集成元组并返回它们的和
- 用解包交换两个变量的值
- 写一个函数,接受一个列表,返回其中出现次数最多的元素(提示:可以用 collections.Counter)
有哪部分你觉得还不够清楚,或者想看更详细的代码案例(比如函数装饰器、列表排序高级技巧、元组作为 dict key 的实际应用等),可以直接告诉我!