379 lines
7.7 KiB
Markdown
379 lines
7.7 KiB
Markdown
---
|
|
doc_type: short
|
|
full_text: sources/02_Containers.md
|
|
---
|
|
|
|
# 02_Containers 总结
|
|
|
|
本文介绍 Python 中三类核心Python容器:列表、字典和集合,并通过股票投资组合与价格数据的读取练习,展示如何选择合适的数据结构来组织、查询和计算数据。
|
|
|
|
## 核心主题
|
|
|
|
程序经常需要处理大量对象,例如:
|
|
|
|
- 股票投资组合
|
|
- 股票价格表
|
|
- 多行 CSV 数据记录
|
|
|
|
Python 常用的三种容器选择是:
|
|
|
|
| 容器 | 特点 | 典型用途 |
|
|
|---|---|---|
|
|
| `list` | 有序,可包含任意对象 | 保存顺序重要的记录集合 |
|
|
| `dict` | 通过键快速查找值 | 根据名称、编号等键查询数据 |
|
|
| `set` | 无序、元素唯一 | 成员测试、去重、集合运算 |
|
|
|
|
## 列表作为容器
|
|
|
|
当数据顺序重要时,应使用列表。列表可以保存任意对象,包括元组、字典等复合结构。
|
|
|
|
示例:用列表保存股票持仓,每条记录是一个元组:
|
|
|
|
```python
|
|
portfolio = [
|
|
('GOOG', 100, 490.1),
|
|
('IBM', 50, 91.3),
|
|
('CAT', 150, 83.44)
|
|
]
|
|
```
|
|
|
|
可以通过整数索引访问:
|
|
|
|
```python
|
|
portfolio[0] # ('GOOG', 100, 490.1)
|
|
portfolio[2] # ('CAT', 150, 83.44)
|
|
```
|
|
|
|
## 构造列表
|
|
|
|
列表通常从空列表开始,通过 `.append()` 添加元素:
|
|
|
|
```python
|
|
records = []
|
|
records.append(('GOOG', 100, 490.10))
|
|
records.append(('IBM', 50, 91.3))
|
|
```
|
|
|
|
从文件读取 CSV 数据时,可以逐行解析并追加到列表中:
|
|
|
|
```python
|
|
records = []
|
|
|
|
with open('Data/portfolio.csv', 'rt') as f:
|
|
next(f) # 跳过表头
|
|
for line in f:
|
|
row = line.split(',')
|
|
records.append((row[0], int(row[1]), float(row[2])))
|
|
```
|
|
|
|
这一模式是后续练习中 `read_portfolio(filename)` 的基础。
|
|
|
|
## 字典作为容器
|
|
|
|
字典适合需要根据键进行快速随机查找的场景。例如,用股票代码查找价格:
|
|
|
|
```python
|
|
prices = {
|
|
'GOOG': 513.25,
|
|
'CAT': 87.22,
|
|
'IBM': 93.37,
|
|
'MSFT': 44.12
|
|
}
|
|
```
|
|
|
|
访问方式:
|
|
|
|
```python
|
|
prices['IBM']
|
|
prices['GOOG']
|
|
```
|
|
|
|
与列表通过整数位置访问不同,字典通过具有语义的键访问,常让代码更清晰。
|
|
|
|
## 构造字典
|
|
|
|
字典可以从空字典开始构造:
|
|
|
|
```python
|
|
prices = {}
|
|
prices['GOOG'] = 513.25
|
|
prices['CAT'] = 87.22
|
|
prices['IBM'] = 93.37
|
|
```
|
|
|
|
从文件读取价格数据时,可以将股票名作为键、价格作为值:
|
|
|
|
```python
|
|
prices = {}
|
|
|
|
with open('Data/prices.csv', 'rt') as f:
|
|
for line in f:
|
|
row = line.split(',')
|
|
prices[row[0]] = float(row[1])
|
|
```
|
|
|
|
文中提醒:`Data/prices.csv` 末尾可能存在空行,直接转换可能导致程序崩溃。因此读取真实文件时应处理空行或异常。这引出[[concepts/异常处理]]与数据清洗问题。
|
|
|
|
## 字典查找
|
|
|
|
可以用 `in` 判断键是否存在:
|
|
|
|
```python
|
|
if key in d:
|
|
# 存在
|
|
else:
|
|
# 不存在
|
|
```
|
|
|
|
也可以用 `.get()` 提供默认值,避免键不存在时报错:
|
|
|
|
```python
|
|
name = d.get(key, default)
|
|
```
|
|
|
|
示例:
|
|
|
|
```python
|
|
prices.get('IBM', 0.0) # 93.37
|
|
prices.get('SCOX', 0.0) # 0.0
|
|
```
|
|
|
|
这在计算投资组合当前市值时很有用,因为某些股票代码可能不在价格字典中。
|
|
|
|
## 复合键
|
|
|
|
Python 字典的键必须是不可变对象。元组可以作为字典键,因此适合表达复合索引:
|
|
|
|
```python
|
|
holidays = {
|
|
(1, 1): 'New Years',
|
|
(3, 14): 'Pi day',
|
|
(9, 13): "Programmer's day",
|
|
}
|
|
```
|
|
|
|
访问时:
|
|
|
|
```python
|
|
holidays[3, 14]
|
|
```
|
|
|
|
列表、集合和字典不能作为键,因为它们是可变对象。这体现了可变性与不可变性在 Python 数据结构设计中的重要性。
|
|
|
|
## 集合
|
|
|
|
集合是无序且元素唯一的容器:
|
|
|
|
```python
|
|
tech_stocks = {'IBM', 'AAPL', 'MSFT'}
|
|
```
|
|
|
|
也可以用 `set()` 构造:
|
|
|
|
```python
|
|
tech_stocks = set(['IBM', 'AAPL', 'MSFT'])
|
|
```
|
|
|
|
集合常用于成员测试:
|
|
|
|
```python
|
|
'IBM' in tech_stocks # True
|
|
'FB' in tech_stocks # False
|
|
```
|
|
|
|
也常用于去重:
|
|
|
|
```python
|
|
names = ['IBM', 'AAPL', 'GOOG', 'IBM', 'GOOG', 'YHOO']
|
|
unique = set(names)
|
|
```
|
|
|
|
## 集合操作
|
|
|
|
集合支持常见的数学集合运算:
|
|
|
|
```python
|
|
unique.add('CAT')
|
|
unique.remove('YHOO')
|
|
|
|
s1 = {'a', 'b', 'c'}
|
|
s2 = {'c', 'd'}
|
|
|
|
s1 | s2 # 并集 {'a', 'b', 'c', 'd'}
|
|
s1 & s2 # 交集 {'c'}
|
|
s1 - s2 # 差集 {'a', 'b'}
|
|
```
|
|
|
|
这些操作适合用于比较不同数据源中的名称、代码或记录集合。
|
|
|
|
## 练习 2.4:元组列表表示投资组合
|
|
|
|
练习要求在 `Work/report.py` 中实现:
|
|
|
|
```python
|
|
def read_portfolio(filename):
|
|
...
|
|
```
|
|
|
|
该函数读取 `Data/portfolio.csv`,并返回一个由元组组成的列表:
|
|
|
|
```python
|
|
[
|
|
('AA', 100, 32.2),
|
|
('IBM', 50, 91.1),
|
|
...
|
|
]
|
|
```
|
|
|
|
每个元组包含:
|
|
|
|
1. 股票名
|
|
2. 股数
|
|
3. 买入价格
|
|
|
|
可以通过二维索引访问:
|
|
|
|
```python
|
|
portfolio[row][column]
|
|
```
|
|
|
|
也可以通过元组解包让代码更清晰:
|
|
|
|
```python
|
|
total = 0.0
|
|
for name, shares, price in portfolio:
|
|
total += shares * price
|
|
```
|
|
|
|
该练习体现了CSV文件处理、数据建模和序列解包。
|
|
|
|
## 练习 2.5:字典列表表示投资组合
|
|
|
|
练习要求将每条股票记录从元组改为字典:
|
|
|
|
```python
|
|
{
|
|
'name': 'AA',
|
|
'shares': 100,
|
|
'price': 32.2
|
|
}
|
|
```
|
|
|
|
整体结构变成“字典的列表”:
|
|
|
|
```python
|
|
[
|
|
{'name': 'AA', 'shares': 100, 'price': 32.2},
|
|
{'name': 'IBM', 'shares': 50, 'price': 91.1},
|
|
...
|
|
]
|
|
```
|
|
|
|
访问字段时不再依赖数字列号,而是通过字段名:
|
|
|
|
```python
|
|
portfolio[1]['shares']
|
|
```
|
|
|
|
计算总成本:
|
|
|
|
```python
|
|
total = 0.0
|
|
for s in portfolio:
|
|
total += s['shares'] * s['price']
|
|
```
|
|
|
|
这种结构更可读,也更接近现实中的结构化记录。调试较大的列表或字典时,可以使用:
|
|
|
|
```python
|
|
from pprint import pprint
|
|
pprint(portfolio)
|
|
```
|
|
|
|
## 练习 2.6:用字典保存价格表
|
|
|
|
练习要求实现:
|
|
|
|
```python
|
|
def read_prices(filename):
|
|
...
|
|
```
|
|
|
|
该函数读取 `Data/prices.csv`,返回一个价格字典:
|
|
|
|
```python
|
|
{
|
|
'IBM': 106.28,
|
|
'MSFT': 20.89,
|
|
...
|
|
}
|
|
```
|
|
|
|
此结构适合根据股票代码快速查询当前价格:
|
|
|
|
```python
|
|
prices['IBM']
|
|
prices['MSFT']
|
|
```
|
|
|
|
文中特别强调 `prices.csv` 可能包含空行,使用 `csv.reader()` 时空行会产生空列表:
|
|
|
|
```python
|
|
[]
|
|
```
|
|
|
|
因此实现时需要考虑:
|
|
|
|
- 用 `if` 判断跳过无效行
|
|
- 或用 `try/except` 捕获异常
|
|
|
|
这部分是对健壮文件读取的入门实践。
|
|
|
|
## 练习 2.7:计算投资组合盈亏
|
|
|
|
最后一个练习要求把前面的两个结构结合起来:
|
|
|
|
- `read_portfolio()` 返回持仓列表
|
|
- `read_prices()` 返回当前价格字典
|
|
|
|
然后计算:
|
|
|
|
1. 投资组合原始成本
|
|
2. 当前市场价值
|
|
3. 盈利或亏损
|
|
|
|
这展示了列表与字典的互补关系:
|
|
|
|
- 列表保存多条持仓记录
|
|
- 字典根据股票代码快速查找当前价格
|
|
|
|
该模式是后续更完整报表程序的基础。
|
|
|
|
## 关键收获
|
|
|
|
- 列表适合保存有序记录集合。
|
|
- 元组可用于表示固定字段的简单记录。
|
|
- 字典适合通过语义化键访问字段或快速查找数据。
|
|
- 集合适合去重、成员测试和集合运算。
|
|
- 字典键必须是不可变对象,元组可以作为复合键。
|
|
- 真实文件输入可能包含空行或坏数据,程序需要防御性处理。
|
|
- 使用字典列表表示结构化记录通常比元组列表更易读。
|
|
- 股票投资组合示例展示了Python数据结构在实际数据处理中的组合使用。
|
|
|
|
## Related Concepts
|
|
- [[concepts/集合与集合运算]]
|
|
- [[concepts/Python-容器]]
|
|
- [[concepts/列表与序列]]
|
|
- [[concepts/字典与数据建模]]
|
|
- [[concepts/CSV-数据处理]]
|
|
- [[concepts/元组与解包]]
|
|
- [[concepts/文件读写]]
|
|
- [[concepts/上下文管理器]]
|
|
- [[concepts/Python-可变对象]]
|
|
- [[concepts/Python-不可变对象]]
|
|
- [[concepts/字符串处理]]
|
|
- [[concepts/函数]]
|
|
- [[concepts/模块与-import]]
|
|
- [[concepts/Python-交互式解释器]]
|
|
- [[concepts/测试-日志与调试]]
|