Python 进阶:元组、字典、集合与函数全解析
在掌握了 Python 基本语法和数据类型之后,接下来进入更丰富的容器类型与代码组织方式的学习。本文聚焦三大数据结构------元组、字典、集合,以及函数的核心概念,包括推导式、可变与不可变、参数类型、作用域和匿名函数,帮助你构建更完整的基础知识体系。
一、元组与推导式
1. 元组(tuple)
元组是与列表相似的序列类型,但有一个关键区别:不可变。一旦创建,不能修改、增加或删除元素,因此被称为"只读"序列。
python
t = (1, 2, 3, 4)
print(t[0]) # 1
print(t[1:3]) # (2, 3)
元组适合存储不希望被意外改动的数据,例如函数返回多个值时,底层就是元组。
单元素元组需要在元素后加逗号:
(1,),否则会被当作普通括号包裹的运算。
2. 列表推导式
列表推导式是快速生成列表的简洁语法。
语法:
python
new_list = [expression for item in iterable if condition]
示例:生成 1 到 10 中所有偶数的平方
python
even_squares = [x**2 for x in range(1, 11) if x % 2 == 0]
print(even_squares) # [4, 16, 36, 64, 100]
它会在内存中直接生成完整的列表,适合结果集不太大的场景。
3. 生成器表达式
当数据量极大时,可以用生成器表达式替代列表推导式。它将表达式包裹在圆括号 中,返回一个生成器对象,采用惰性计算------直到被访问时才生成下一个元素,极大节省内存。
python
gen = (x**2 for x in range(1, 1000000) if x % 2 == 0)
print(next(gen)) # 4
print(next(gen)) # 16
两者对比如下:
| 特点 | 列表推导式 | 生成器表达式 |
|---|---|---|
| 返回类型 | 列表 | 生成器对象 |
| 内存占用 | 一次生成全部,内存占用大 | 按需生成,内存友好 |
| 访问方式 | 可索引、可重复遍历 | 只能用 next() 或一次性遍历 |
| 适用场景 | 结果集较小、需多次使用 | 结果集巨大、只需遍历一次 |
二、字典(dict)
字典是 Python 中非常重要的映射类型,以键值对的形式存储数据,具有极高的查询效率。
1. 字典的定义与特点
python
person = {'name': 'john', 'job': 'policeman'}
- 键必须是不可变类型,如字符串、数字、元组(包含不可变元素的元组)。
- 字典本身是可变的,可以动态增删键值对。
- 在 Python 3.7+ 中,字典保持插入顺序,但作为映射结构,逻辑上仍按键访问。
2. 常用操作
python
d = {'a': 1, 'b': 2, 'c': 3}
# 获取所有键
print(d.keys()) # dict_keys(['a', 'b', 'c'])
# 获取所有键值对(元组形式)
print(d.items()) # dict_items([('a', 1), ('b', 2), ('c', 3)])
# 遍历字典
for k, v in d.items():
print(f"{k}: {v}")
3. 字典推导式
与列表推导式类似,字典也可以快速构建:
python
squares = {x: x**2 for x in range(1, 6)}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
结合条件筛选:
python
even_squares = {x: x**2 for x in range(1, 11) if x % 2 == 0}
三、集合(set)
集合是一个无序、不重复的元素容器,常用于去重和数学集合运算。
1. 集合的定义
python
s = {1, 2, 3}
empty_set = set() # 空集合必须用 set(),{} 创建的是空字典
- 集合中的元素也必须是不可变类型(数字、字符串、元组)。
- 集合本身是可变的,可以添加和删除元素。
2. 集合推导式
python
s = {x for x in 'abracadabra' if x not in 'abc'}
print(s) # {'r', 'd'}
由于集合去重,结果中每个字符只出现一次。
四、变量赋值与可变性
在使用变量时,需理解赋值背后的引用机制。
python
B = [1, 2, 3]
A = B # A 和 B 指向同一块内存
- 若
B是不可变类型 (如整数、字符串、元组),B被修改后将指向新地址,A不受影响。 - 若
B是可变类型 (如列表、字典),原地修改B会影响A,因为它们仍指向同一对象。
理解这一点对于函数传参和行为预测至关重要。
五、函数的定义与参数
函数是封装代码、提高复用性的基础。Python 中函数通过 def 关键字定义。
python
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # 调用函数
1. 参数类型
Python 函数的参数非常灵活,共有四类:
| 类型 | 示例 | 说明 |
|---|---|---|
| 位置参数 | def f(a, b): |
按位置依次传入 |
| 默认参数 | def f(a, b=10): |
调用时可不传,使用默认值 |
| 关键字参数 | def f(a, b, d): |
调用时指定参数名,如 f(d=5, a=1, b=2) |
| 可变参数 | def f(*args, **kwargs): |
*args 接收多余位置参数为元组,**kwargs 接收关键字参数为字典 |
2. 参数组合顺序
当多种参数混合时,顺序有严格规定:
位置参数 → 默认参数 → *args → 关键字参数 → **kwargs
示例:
python
def demo(a, b, c=3, *args, d, e=10, **kwargs):
print(a, b, c, args, d, e, kwargs)
demo(1, 2, 4, 5, 6, d=7, e=8, x=9, y=10)
# 输出:1 2 4 (5, 6) 7 8 {'x': 9, 'y': 10}
处理函数时,遵循此顺序可避免歧义和错误。
六、作用域与 LEGB 规则
变量的可见范围由作用域决定,Python 遵循 LEGB 查找顺序:
| 作用域 | 英文 | 说明 |
|---|---|---|
| L | Local | 函数内部 |
| E | Enclosing | 嵌套外层(如有嵌套函数) |
| G | Global | 全局作用域 |
| B | Built-in | 内置作用域(如 print、len) |
当使用一个变量时,Python 按照 L → E → G → B 的顺序逐层查找。
global 与 nonlocal
- global:在函数内部声明某变量为全局变量,可对其进行重新赋值。
python
x = 10
def change():
global x
x = 20
change()
print(x) # 20
- nonlocal:用于嵌套函数,声明变量来自外层函数(非全局),可在内层修改外层局部变量。
python
def outer():
count = 0
def inner():
nonlocal count
count += 1
return count
return inner
f = outer()
print(f()) # 1
print(f()) # 2
七、匿名函数 lambda
lambda 用于创建没有名字的小型函数,只包含一个表达式,结果自动返回。
语法:
python
lambda 参数: 表达式
正常使用:
python
add = lambda x: x + 1
print(add(1)) # 2
高阶函数应用:
lambda 最常见的场景是作为 sorted、map、filter 等函数的 key 参数。
python
students = [{'name': 'Tom', 'score': 92}, {'name': 'Jerry', 'score': 85}]
sorted_students = sorted(students, key=lambda s: s['score'], reverse=True)
print(sorted_students)
# [{'name': 'Tom', 'score': 92}, {'name': 'Jerry', 'score': 85}]
此处 key 指定比较的值,sorted 会逐个将列表元素传给 lambda 函数,用返回的结果进行排序。
小结
本文在基本语法和数据类型之上,补齐了 Python 中元组、字典、集合三种核心容器的用法,同时深入探讨了推导式与生成器表达式的效率差异。函数部分覆盖了从定义、丰富参数类型到作用域和匿名函数的完整链路,其中 LEGB 规则和 global/nonlocal 是理解 Python 变量行为的关键。
将这些知识组合起来,你已经具备了处理大多数基础任务的能力。下一步建议多练多写,将推导式与函数结合,逐步培养 Pythonic 的编码风格。