1.Python虚拟环境 #
1.1 什么是虚拟环境? #
- 核心概念:为每个 Python 项目创建独立的运行环境,包含:
- 专属的 Python 解释器副本
- 独立的包安装目录(
site-packages) - 隔离的环境变量(如
PATH)
- 解决的问题:
- 不同项目依赖不同版本的包(如 Django 2.x vs 3.x)
- 避免全局包污染
- 精确控制项目依赖
1.2 为什么需要虚拟环境? #
| 场景 | 无虚拟环境 | 使用虚拟环境 |
|---|---|---|
| 项目A 需 requests==2.25 | 全局安装后影响所有项目 | 仅影响当前项目 |
| 项目B 需 requests==3.0 | 版本冲突导致报错 | 独立版本无冲突 |
| 部署项目 | 需手动整理依赖 | pip freeze > requirements.txt |
1.3 创建虚拟环境 #
# 创建名为 .venv 的虚拟环境(推荐隐藏目录)
python -m venv .venv目录结构:
.venv/
├── bin/ # Linux/macOS 脚本
│ ├── python # 专属解释器
│ ├── pip # 专属包管理器
│ └── activate # 激活脚本
├── Scripts/ # Windows 脚本
│ ├── python.exe
│ ├── pip.exe
│ └── activate.bat
└── Lib/ # 安装的包存放位置
└── site-packages/1.4 激活虚拟环境 #
- Windows (CMD/PowerShell):
.venv\Scripts\activate.bat # CMD .venv\Scripts\Activate.ps1 # PowerShell (需管理员权限执行: Set-ExecutionPolicy RemoteSigned) - Linux/macOS:
激活后提示符变化:source .venv/bin/activate(.venv) user@host:~$ # 出现环境名前缀
1.5 使用虚拟环境 #
# 检查当前 Python 路径(确认环境生效)
(.venv) $ which python
/path/to/.venv/bin/python
# 安装项目专属包(不影响全局)
(.venv) $ pip install requests pandas
# 导出依赖清单(部署关键步骤)
(.venv) $ pip freeze > requirements.txt1.6 退出虚拟环境 #
(.venv) $ deactivate # 所有平台通用1.7 重建环境 #
# 1. 创建新环境
python -m venv .venv
# 2. 激活环境
source .venv/bin/activate # Linux/macOS
# 3. 安装所有依赖
(.venv) $ pip install -r requirements.txt1.8 虚拟环境管理最佳实践 #
- 环境命名:
- 推荐使用
.venv(隐藏目录避免误操作) - 或
venv(Python 社区惯例)
- 推荐使用
- .gitignore 配置:
# 忽略虚拟环境目录 .venv/ venv/ - 依赖管理:
- 每次安装/卸载包后更新
requirements.txt - 使用
pip freeze --local > requirements.txt避免包含全局包
- 每次安装/卸载包后更新
1.9 常见问题解决 #
- 虚拟环境激活失败:
- Windows:检查执行策略
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser - 路径错误:确保在项目根目录执行
- Windows:检查执行策略
- 包安装位置异常:
- 检查提示符是否有
(.venv)前缀 - 运行
python -m site查看包路径
- 检查提示符是否有
关键总结:虚拟环境是 Python 开发的基石,通过隔离依赖保证项目可移植性和稳定性。务必在开始新项目时优先创建环境!
2. 列表推导式与生成器表达式 #
2.1 列表推导式 #
2.1.1 基本语法 #
[expression for item in iterable if condition]2.1.2 特点 #
- 立即执行:创建时会立即计算所有元素并生成完整的列表
- 内存占用:所有元素都存储在内存中
- 可重复使用:可以多次遍历、索引访问
- 语法标识:使用方括号
[]
2.1.3 示例 #
# 生成1-10的平方列表
squares = [x**2 for x in range(1, 11)]
print(squares) # 输出: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 带条件的列表推导式
even_squares = [x**2 for x in range(1, 11) if x % 2 == 0]
print(even_squares) # 输出: [4, 16, 36, 64, 100]2.1.4 适用场景 #
- 需要立即使用所有元素的场合
- 需要多次访问或修改结果的场合
- 数据量不大,内存足够的情况
2.2 生成器表达式 #
2.2.1 基本语法 #
(expression for item in iterable if condition)2.2.2 特点 #
- 惰性求值:只在需要时才生成元素(按需计算)
- 内存高效:一次只生成一个元素,不占用大量内存
- 一次性使用:生成器只能迭代一次,迭代完就"耗尽"
- 语法标识:使用圆括号
()
2.2.3 示例 #
# 生成1-10的平方生成器
squares_gen = (x**2 for x in range(1, 11))
print(squares_gen) # 输出: <generator object <genexpr> at 0x...>
# 使用生成器
for num in squares_gen:
print(num, end=' ') # 输出: 1 4 9 16 25 36 49 64 81 100
# 生成器只能迭代一次
print(list(squares_gen)) # 输出: [] (因为已经耗尽)2.2.4 适用场景 #
- 处理大量数据或无限序列
- 只需要单次遍历的情况
- 数据流处理或管道操作
- 内存受限的环境
2.3 核心区别对比 #
| 特性 | 列表推导式 | 生成器表达式 |
|---|---|---|
| 执行时机 | 立即执行 | 惰性求值 |
| 内存使用 | 高(存储所有元素) | 低(逐个生成元素) |
| 可重用性 | 可多次使用 | 只能使用一次 |
| 语法 | 方括号[] |
圆括号() |
| 返回类型 | 列表(list) | 生成器(generator) |
| 适用数据量 | 适合小到中等数据量 | 适合大数据量或无限序列 |
2.4 性能考虑 #
import sys
# 内存占用比较
lst = [x for x in range(100000)]
gen = (x for x in range(100000))
print(sys.getsizeof(lst)) # 较大,如900112字节
print(sys.getsizeof(gen)) # 很小,如208字节2.5 高级用法 #
2.5.1 嵌套推导式 #
# 列表推导式
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
# 生成器表达式
flattened_gen = (num for row in matrix for num in row)2.5.2 与函数结合 #
# 列表推导式 + sum
total = sum([x**2 for x in range(1000)])
# 更高效的写法 - 使用生成器表达式
total = sum(x**2 for x in range(1000)) # 不需要额外的内存存储列表2.6 选择建议 #
使用列表推导式当:
- 需要多次访问结果
- 需要列表特有的方法(如索引、切片)
- 数据量不大
使用生成器表达式当:
- 处理大量或无限数据
- 只需要单次遍历
- 作为其他函数的参数(如sum(), max()等)
- 内存使用是关键考虑因素
3. r #
在 Python 字符串中,前缀 r 表示 原始字符串(Raw String),它会忽略字符串中的转义字符(如 \n, \t, \ 等),直接按照字面内容处理。
3.1 为什么需要 r? #
在 Windows 文件路径中,反斜杠 \ 是默认的路径分隔符(如 C:\Program Files\...)。但 Python 中 \ 是转义字符的标志,会导致以下问题:
3.1.1 无 r 的情况 #
path = 'C:\Program Files\Google\Chrome\Application\chrome.exe'
print(path)输出(\P 和 \A 被错误转义):
C:\Program Files\Google\Chrome\Application\chrome.exe
# 实际可能报错:`\P` 和 `\A` 是非法的转义序列!3.1.2 使用 r #
path = r'C:\Program Files\Google\Chrome\Application\chrome.exe'
print(path) # 正确输出原始路径3.2 原始字符串的作用 #
禁用转义:
r会让 Python 将\当作普通字符,而非转义符号。
(例如\n会直接显示为两个字符\和n,而非换行符)。兼容 Windows 路径:
避免手动将每个\写成\\(如'C:\\Program Files\\...')。正则表达式友好:
正则表达式中常用\(如\d匹配数字),原始字符串能简化写法:# 无 r:必须写双反斜杠 regex = '\\d+\\w+' # 有 r:直接写单反斜杠 regex = r'\d+\w+'
3.3 注意事项 #
不能以奇数个
\结尾:path = r'C:\temp\' # 错误!末尾的 `\` 会转义后续引号解决方法:
path = r'C:\temp' + '\\' # 或使用正斜杠 `/`正斜杠
/是更好的替代方案:
Python 也支持 Unix 风格的路径分隔符(Windows 同样兼容):path = 'C:/Program Files/Google/Chrome/chrome.exe' # 无需 r
3.4 总结 #
| 场景 | 写法 | 说明 |
|---|---|---|
| Windows 路径 | r'C:\path\to\file' |
防止 \ 转义 |
| 正则表达式 | r'\d+' |
简化 \ 处理 |
| 跨平台路径 | 'C:/path/to/file' |
优先推荐(无需 r) |
使用 r 能让你在 Windows 路径和正则表达式中避免转义字符的麻烦!
4. 字典解包 #
4.1 字典解包操作符 #
是 Python 的 字典解包操作符**,它的作用是将字典的键值解包为关键字参数
4.2 具体解释 #
假设
job_data的结构:job_data = { 'position': 'Python工程师', 'company': '某科技公司', 'city': '北京', 'experience': '3-5年', 'education': '本科', 'postDescription': '负责Python开发...' }`job_data` 的解包效果**:
Job(**job_data) # 等价于: Job( position='Python工程师', company='某科技公司', city='北京', experience='3-5年', education='本科', postDescription='负责Python开发...' )
4.3 为什么这样用? #
便捷性:
- 如果
job_data的键名与Job类的属性名完全一致,直接解包可以避免手动逐个字段赋值。 - 适合从外部数据源(如 API 返回的 JSON 或表单数据)直接创建模型实例。
- 如果
动态字段匹配:
- 即使
job_data中包含Job类没有的额外键,SQLAlchemy 会忽略这些键(不会报错)。 - 如果缺少某些键,对应的字段会设为
None(因为模型中字段通常设置了nullable=True)。
- 即使
4.4 注意事项 #
键名必须匹配:
job_data的键名必须与Job类的属性名完全一致(区分大小写)。- 如果键名不匹配,对应的字段不会被赋值(例如键名是
job_title而非position)。
安全性
- 如果
job_data来自不可信来源(如用户输入),直接解包可能有风险(如注入攻击)。建议先过滤或验证数据:valid_fields = {'position', 'company', 'city', 'experience', 'education', 'postDescription'} filtered_data = {k: v for k, v in job_data.items() if k in valid_fields} session.add(Job(**filtered_data))
- 如果
替代方案
- 如果不想用解包,也可以手动创建对象:
job = Job( position=job_data['position'], company=job_data['company'], # 其他字段... ) session.add(job)
- 如果不想用解包,也可以手动创建对象:
4.5 示例场景 #
假设从 BOSS 直聘 API 获取到一个职位数据的字典,可以直接转换为 SQLAlchemy 对象并存入数据库:
# 模拟 API 返回的数据
job_data = {
'position': '数据分析师',
'company': '某互联网公司',
'city': '上海',
'experience': '1-3年',
'education': '硕士',
'postDescription': '负责用户行为分析...'
}
# 直接解包创建并保存
session.add(Job(**job_data))
session.commit()4.6 总结: #
**job_data 是一种 Python 的语法糖,用于简化字典到关键字参数的转换,特别适合将外部数据快速映射到 SQLAlchemy 模型。它的核心作用是将字典的键值对拆解为独立的命名参数,使代码更简洁。
5. 对象和字典 #
在 Python 中,对象(Object) 和 字典(Dictionary,dict) 都可以存储数据,但它们在设计、用途和功能上有显著的区别。
5.1 基本定义 #
| 特性 | 字典(dict) |
对象(object) |
|---|---|---|
| 类型 | 内置数据类型 (dict) |
类的实例(class instance) |
| 存储方式 | 键值对(key-value) |
属性(attribute)和方法(method) |
| 键/属性名 | 必须是 可哈希 类型(如 str, int, tuple) |
可以是任意合法的 Python 标识符 |
| 动态性 | 可以随时添加、删除键值对 | 属性通常由类定义,但可以动态添加(不推荐) |
| 访问方式 | dict["key"] 或 dict.get("key") |
obj.attribute 或 getattr(obj, "attr") |
5.2 访问数据的方式 #
字典 #
person = {"name": "Alice", "age": 25}
# 访问
print(person["name"]) # "Alice"
print(person.get("age")) # 25
# 修改
person["age"] = 26
person["city"] = "New York" # 新增键值对对象 #
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 25)
# 访问
print(person.name) # "Alice"
print(getattr(person, "age")) # 25
# 修改
person.age = 26
person.city = "New York" # 动态添加属性(可行但不推荐)5.3 主要区别 #
| 区别 | 字典(dict) |
对象(object) |
|---|---|---|
| 设计目的 | 通用的键值存储结构 | 面向对象编程(OOP),封装数据和行为 |
| 键/属性限制 | 键必须是可哈希的 | 属性名必须是合法的 Python 标识符 |
| 方法 | 无方法,仅存储数据 | 可以定义方法(obj.method()) |
| 继承和多态 | 不支持 | 支持(OOP 特性) |
| 访问速度 | 极快(哈希表实现) | 稍慢(涉及属性查找) |
| 动态扩展 | 可随意增删键值对 | 可以动态添加属性,但通常不建议 |
5.4 何时使用字典 vs 对象? #
使用字典的情况: #
- 需要 快速存储和检索键值对(如 JSON 数据)。
- 键是动态的(如从外部数据源读取)。
- 不需要关联方法(纯数据存储)。
使用对象的情况: #
- 需要 封装数据和行为(如
person.greet())。 - 需要 继承、多态等 OOP 特性。
- 属性名是固定的(由类定义),而不是动态生成的。
5.5 相互转换 #
字典 → 对象 #
class DictToObj:
def __init__(self, dictionary):
for key, value in dictionary.items():
setattr(self, key, value)
data = {"name": "Bob", "age": 30}
person = DictToObj(data)
print(person.name) # "Bob"或使用 types.SimpleNamespace:
from types import SimpleNamespace
data = {"name": "Bob", "age": 30}
person = SimpleNamespace(**data)
print(person.age) # 30对象 → 字典 #
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 25)
person_dict = vars(person) # {'name': 'Alice', 'age': 25}或手动提取:
person_dict = {key: getattr(person, key) for key in dir(person) if not key.startswith("__")}5.6 总结 #
- 字典(
dict) 是 Python 内置的高效键值存储结构,适合存储动态数据。 - 对象(
object) 是面向对象编程的核心,可以封装数据和行为,适合更复杂的逻辑。 - 如果你只是存储数据,用
dict;如果需要方法和类结构,用object。
6. repr #
__repr__ 是 Python 类的一个特殊方法(magic method/dunder method),用于定义对象的"官方"字符串表示形式。它对于调试、日志记录和开发过程中的对象展示非常重要。
6.1 基本概念 #
什么是 __repr__? #
__repr__ 方法应该返回一个字符串,这个字符串理论上应该是一个有效的 Python 表达式,可以用来重新创建该对象(如果可能的话)。
何时调用 __repr__? #
- 当在交互式解释器中直接输入对象名称时
- 当使用
repr()函数时 - 当对象被包含在容器中(如列表、字典)并被打印时
- 当没有定义
__str__方法时,调用print()或str()也会回退到__repr__
6.2 基本语法 #
class MyClass:
def __repr__(self):
return "字符串表示"6.3 示例分析 #
在你提供的 Job 类中:
def __repr__(self):
"""返回职位的字符串表示"""
return f"<Job(position='{self.position}', company='{self.company}', city='{self.city}')>"这是一个良好的 __repr__ 实现,因为它:
- 包含了类名
- 显示了关键属性
- 使用了一种常见的格式(尖括号包裹)
6.4 最佳实践 #
1. 内容要求 #
- 明确性:应该包含足够的信息来区分不同对象
- 准确性:应该准确反映对象的状态
- 可重现性(理想情况下):最好能返回一个字符串,可以被
eval()用来重建对象
2. 格式建议 #
- 通常用尖括号
< >包裹 - 包含类名
- 显示关键属性
3. 与 __str__ 的区别 #
| 特性 | __repr__ |
__str__ |
|---|---|---|
| 目的 | 明确的、无歧义的对象表示 | 可读性好的、简洁的对象表示 |
| 使用场景 | 调试、日志、开发者 | 终端用户输出 |
| 必须性 | 应该总是实现 | 可选实现 |
| 调用方式 | repr(obj) 或交互式解释器中直接输入 |
str(obj) 或 print(obj) |
6.5 实际示例 #
好的 __repr__ 示例 #
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
def __str__(self):
return f"({self.x}, {self.y})"
p = Point(3, 4)
print(repr(p)) # 输出: Point(x=3, y=4)
print(p) # 输出: (3, 4)数据库模型的 __repr__ #
对于 SQLAlchemy 模型,通常只显示关键字段(如你的 Job 类示例):
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(50))
email = Column(String(100))
def __repr__(self):
return f"<User(id={self.id}, username='{self.username}')>"6.6 为什么 __repr__ 重要? #
- 调试:当你在调试或查看日志时,清晰的
__repr__能让你快速了解对象状态 - 开发体验:在交互式环境(如 IPython、Jupyter)中工作时,良好的
__repr__能显著提高效率 - 错误信息:当出现异常时,Python 会使用
__repr__来显示相关对象
6.7 常见错误 #
过于简单:
`python def repr(self):return "Job object" # 没有提供有用信息`zhang过于复杂:
def __repr__(self): return str(self.__dict__) # 可能包含太多不必要的信息忽略某些属性:
def __repr__(self): return f"<Job(name='{self.name}')>" # 缺少其他关键属性
6.8 总结 #
__repr__是 Python 对象的重要方法,应该为每个类实现- 它应该返回一个明确、无歧义的字符串表示
- 对于数据类或模型类,通常包含类名和关键属性
- 与
__str__不同,__repr__更侧重于开发者而非终端用户 - 良好的
__repr__实现可以显著提高开发和调试效率
7.rsplit #
rsplit() 是 Python 字符串(str)对象的一个内置方法,用于从字符串的右侧开始分割字符串。它是 split() 方法的"从右开始"版本。
7.1 基本语法 #
str.rsplit(sep=None, maxsplit=-1)参数说明: #
- sep (可选):分隔符,默认为所有的空白字符(包括空格、换行符
\n、制表符\t等) - maxsplit (可选):最大分割次数,默认为-1(表示不限制分割次数)
返回值: #
返回一个列表,包含分割后的子字符串
7.2 与 split() 的区别 #
| 方法 | 分割方向 | 分割顺序 | 结果顺序 |
|---|---|---|---|
split() |
从左向右 | 从前往后 | 保持原序 |
rsplit() |
从右向左 | 从后往前 | 保持原序 |
7.3 使用示例 #
1. 基本使用 #
text = "apple banana cherry date"
# 默认从右侧按空格分割(效果与 split 相同)
print(text.rsplit()) # ['apple', 'banana', 'cherry', 'date']
# 限制分割次数
print(text.rsplit(maxsplit=2)) # ['apple banana', 'cherry', 'date']2. 指定分隔符 #
data = "John,Doe,30,New York"
# 从右侧分割
print(data.rsplit(',', 2)) # ['John,Doe', '30', 'New York']3. 处理文件路径 #
path = "/home/user/documents/file.txt"
# 获取文件名
filename = path.rsplit('/', 1)[1]
print(filename) # 'file.txt'
# 获取文件扩展名
basename, ext = filename.rsplit('.', 1)
print(basename) # 'file'
print(ext) # 'txt'4. 处理多行文本 #
lines = """第一行
第二行
第三行"""
# 从右侧分割行
last_two_lines = lines.rsplit('\n', 2)
print(last_two_lines) # ['第一行', '第二行', '第三行']7.4 特殊用例 #
1. 分隔符不存在时 #
text = "hello world"
print(text.rsplit('x')) # ['hello world'] - 返回包含原字符串的列表2. 空字符串处理 #
text = ""
print(text.rsplit()) # [] - 返回空列表3. 连续分隔符 #
text = "a,,b,,c"
print(text.rsplit(',')) # ['a', '', 'b', '', 'c']7.5 性能考虑 #
- 对于简单的从左分割,
split()性能稍好 - 当需要从右侧分割时,
rsplit()比先split()再切片更高效
7.6 实际应用场景 #
- 解析文件路径:获取文件名或扩展名
- 处理日志文件:提取最后几条记录
- 解析CSV数据:从右侧提取特定数量的字段
- 文本处理:从右侧开始分割长文本
7.7 总结 #
rsplit() 是 Python 字符串处理中一个非常有用的方法,特别适用于需要从字符串右侧开始分割的场景。理解它与 split() 的区别,并合理使用 maxsplit 参数,可以让你更高效地处理各种字符串分割需求。
8.三元表达式 #
三元条件表达式是 Python 中的一种简洁的条件赋值语法,它允许你在一行代码中实现简单的 if-else 逻辑。
8.1 基本语法 #
value = true_value if condition else false_value这个表达式等价于:
if condition:
value = true_value
else:
value = false_value8.2 工作原理 #
- 首先评估
condition的布尔值 - 如果
condition为True,整个表达式返回true_value - 如果
condition为False,整个表达式返回false_value
8.3 具体示例 #
示例1:简单的数值比较 #
x = 10
y = 20
# 找出较大的数
max_num = x if x > y else y
print(max_num) # 输出: 208.4 示例2:字符串处理 #
name = "Alice"
# 检查名字长度
description = "长名字" if len(name) > 5 else "短名字"
print(description) # 输出: "短名字"8.5 示例3:列表操作 #
numbers = [1, 2, 3, 4, 5]
# 检查列表是否为空
result = "有元素" if numbers else "空列表"
print(result) # 输出: "有元素"8.6 嵌套三元表达式 #
三元表达式可以嵌套使用,但为了可读性,不建议嵌套太多层:
age = 25
category = "儿童" if age < 13 else "青少年" if age < 18 else "成人"
print(category) # 输出: "成人"等价于:
if age < 13:
category = "儿童"
elif age < 18:
category = "青少年"
else:
category = "成人"8.7 与常规 if-else 的对比 #
| 特性 | 三元表达式 | 常规 if-else |
|---|---|---|
| 简洁性 | 高(一行) | 低(多行) |
| 可读性 | 简单条件时高 | 复杂逻辑时高 |
| 适用场景 | 简单条件赋值 | 复杂条件分支 |
| 可维护性 | 简单条件时好 | 复杂逻辑时好 |
8.8 最佳实践 #
- 保持简单:只用于简单的条件判断
- 避免嵌套:嵌套超过两层会降低可读性
- 优先可读性:如果表达式变得复杂,改用常规 if-else
- 适当使用:在列表推导式或 lambda 函数中特别有用
8.9 实际应用场景 #
变量初始化:
config = user_config if user_config else default_config列表推导式:
numbers = [1, 2, 3, 4, 5] squared = [x**2 if x % 2 == 0 else x for x in numbers] # 结果: [1, 4, 3, 16, 5]函数返回值:
def get_status(score): return "通过" if score >= 60 else "不通过"
三元条件表达式是 Python 中非常有用的语法糖,合理使用可以使代码更加简洁优雅,但要注意不要过度使用而牺牲了代码的可读性。
9.extend #
extend() 是 Python 列表(List)对象的一个内置方法,用于将一个可迭代对象中的所有元素添加到列表的末尾。下面我将从多个角度详细讲解这个方法。
9.1 基本语法 #
list.extend(iterable)list: 要扩展的列表对象iterable: 任何可迭代对象(如列表、元组、集合、字符串、生成器等)- 返回值:
None(直接修改原列表,不返回新列表)
9.2 功能说明 #
extend() 方法会将参数中的可迭代对象的所有元素逐个添加到原列表的末尾,相当于"扩展"了原列表的长度。
9.3 与 append() 方法的区别 #
| 方法 | 作用 | 示例 | 结果 |
|---|---|---|---|
append() |
将整个对象作为一个元素添加 | [1,2].append([3,4]) |
[1, 2, [3, 4]] |
extend() |
将可迭代对象的元素逐个添加 | [1,2].extend([3,4]) |
[1, 2, 3, 4] |
9.4 使用示例 #
9.4.1 示例1:扩展列表 #
numbers = [1, 2, 3]
numbers.extend([4, 5, 6])
print(numbers) # 输出: [1, 2, 3, 4, 5, 6]9.4.2 示例2:扩展元组 #
fruits = ['apple', 'banana']
fruits.extend(('orange', 'grape'))
print(fruits) # 输出: ['apple', 'banana', 'orange', 'grape']9.4.3 示例3:扩展字符串 #
chars = ['a', 'b']
chars.extend('cde')
print(chars) # 输出: ['a', 'b', 'c', 'd', 'e']9.4.4 示例4:扩展集合 #
nums = [1, 2]
nums.extend({3, 4, 5})
print(nums) # 输出可能是: [1, 2, 3, 4, 5] (集合无序)9.4.5 示例5:扩展生成器 #
def gen_numbers():
yield 6
yield 7
nums = [1, 2, 3]
nums.extend(gen_numbers())
print(nums) # 输出: [1, 2, 3, 6, 7]9.5 注意事项 #
原地修改:
extend()会直接修改原列表,而不是返回一个新列表a = [1, 2] b = a.extend([3, 4]) # b是None,a变为[1,2,3,4]参数必须是可迭代对象:
# 错误示例 [1, 2].extend(5) # TypeError: 'int' object is not iterable性能考虑:
extend()比+运算符更高效,特别是处理大数据量时# 不推荐(创建新列表) a = a + b # 推荐(原地修改) a.extend(b)与切片赋值的等价操作:
a = [1, 2] a[len(a):] = [3, 4] # 等价于 a.extend([3,4])
9.6 实际应用场景 #
合并多个列表:
all_items = [] for partial_list in list_of_lists: all_items.extend(partial_list)逐步构建列表:
results = [] for data in data_source: processed = process_data(data) results.extend(processed)扁平化嵌套列表(结合生成器表达式):
nested = [[1,2], [3,4], [5,6]] flat = [] flat.extend(item for sublist in nested for item in sublist) # 结果: [1,2,3,4,5,6]
10.zip #
zip()是Python内置的一个非常有用的函数,它用于将多个可迭代对象(如列表、元组、字符串等)中的元素按顺序配对组合起来。
10.1 基本用法 #
zip()函数的基本语法是:
zip(iterable1, iterable2, ...)它会返回一个zip对象(可迭代的),其中每个元素是一个元组,包含来自各个输入可迭代对象的对应位置的元素。
10.2 示例1:基本配对 #
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
zipped = zip(names, ages)
print(list(zipped)) # 输出: [('Alice', 25), ('Bob', 30), ('Charlie', 35)]10.3 示例2:不同长度的可迭代对象 #
当输入的可迭代对象长度不一致时,zip()会以最短的那个为准:
numbers = [1, 2, 3]
letters = ['a', 'b']
print(list(zip(numbers, letters))) # 输出: [(1, 'a'), (2, 'b')]10.4 解压zip对象 #
可以使用*运算符来"解压"一个zip对象:
zipped = [('Alice', 25), ('Bob', 30), ('Charlie', 35)]
names, ages = zip(*zipped)
print(names) # 输出: ('Alice', 'Bob', 'Charlie')
print(ages) # 输出: (25, 30, 35)10.5 实际应用场景 #
10.5.1. 同时遍历多个列表 #
for name, age in zip(names, ages):
print(f"{name} is {age} years old")10.5.2. 创建字典 #
person_dict = dict(zip(names, ages))
print(person_dict) # 输出: {'Alice': 25, 'Bob': 30, 'Charlie': 35}10.5.3. 矩阵转置 #
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
transposed = list(zip(*matrix))
print(transposed) # 输出: [(1, 4, 7), (2, 5, 8), (3, 6, 9)]10.6 与zip_longest的比较 #
在itertools模块中有一个zip_longest函数,它会以最长的可迭代对象为准,用指定的填充值填充不足的部分:
from itertools import zip_longest
numbers = [1, 2, 3]
letters = ['a', 'b']
print(list(zip_longest(numbers, letters, fillvalue='无')))
# 输出: [(1, 'a'), (2, 'b'), (3, '无')]10.7 注意事项 #
- 在Python 3中,
zip()返回的是一个迭代器,而不是列表。如果需要列表,需要用list()转换。 zip()对象只能迭代一次,如果需要多次使用,应该转换为列表或元组。- 当处理大型数据集时,使用
zip()的迭代器特性可以节省内存。
zip()是Python中处理并行迭代的强大工具,掌握它可以让你写出更简洁、更Pythonic的代码。