以文本形式保存的表格
CSV(逗号分隔值)文件把表格存成文本:一行一条记录,单元格用逗号分隔,通常有一行表头给出列名。价格历史、成交明细以及几乎所有工具的导出都是这种格式。看起来用 line.split(",") 就能解析,但单元格本身可能含有逗号,这时它会被引号包起来:AAPL,"Q3, adjusted"。手工切分在这里会出错,所以请使用标准库的 csv 模块,并用 newline="" 打开文件,以便正确处理单元格内的换行。
import csv
# Write a small table with csv.writer
with open("prices.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow(["date", "symbol", "close", "note"])
writer.writerow(["2025-01-02", "AAPL", 184.25, "Q3, adjusted"])
writer.writerow(["2025-01-03", "AAPL", 185.5, ""])
# The comma inside the note is quoted for us
with open("prices.csv", encoding="utf-8") as file:
print(file.read().splitlines()[1]) # 2025-01-02,AAPL,184.25,"Q3, adjusted"读取行
csv.reader(file) 把每一行作为字符串列表返回。csv.DictReader(file) 先读表头,再把每一行作为以列名为键的字典返回,可读性更好,列顺序变化也不受影响。无论哪种方式,每个单元格都是文本:计算前要用 float(...) 或 int(...) 转换。对使用其他分隔符的文件,传入 delimiter=";"(或 "\t")。
import csv
# DictReader gives each row as a dict; cells are strings
closes = []
with open("prices.csv", newline="", encoding="utf-8") as file:
for row in csv.DictReader(file):
closes.append(float(row["close"]))
print(closes) # [184.25, 185.5]
# csv.reader gives plain lists, header included
with open("prices.csv", newline="", encoding="utf-8") as file:
rows = list(csv.reader(file))
print(rows[0]) # ['date', 'symbol', 'close', 'note']
print(rows[1]) # ['2025-01-02', 'AAPL', '184.25', 'Q3, adjusted']写入行
csv.writer(file).writerow(values) 写入一行,并在需要时加引号,数字会自动转成文本。csv.DictWriter(file, fieldnames=[...]) 写入字典,writeheader() 先写列名。用 "w" 和 newline="" 打开文件;没有 newline="" 时,Windows 上行与行之间可能出现空行。
import csv
# DictWriter: header first, then one dict per row
trades = [{"symbol": "AAPL", "quantity": 200}, {"symbol": "MSFT", "quantity": 50}]
with open("trades.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=["symbol", "quantity"])
writer.writeheader()
writer.writerows(trades)
with open("trades.csv", encoding="utf-8") as file:
print(file.read().splitlines()) # ['symbol,quantity', 'AAPL,200', 'MSFT,50']import csv
# Cells are text until you convert them
with open("prices.csv", newline="", encoding="utf-8") as file:
row = next(csv.DictReader(file))
print(repr(row["close"]), row["close"] * 2) # '184.25' 184.25184.25
print(float(row["close"]) * 2) # 368.5
# Another separator: semicolons
with open("euro.csv", "w", newline="", encoding="utf-8") as file:
csv.writer(file, delimiter=";").writerow(["AAPL", "184,25"])
with open("euro.csv", newline="", encoding="utf-8") as file:
print(next(csv.reader(file, delimiter=";"))) # ['AAPL', '184,25']读回来的全是文本CSV 文件没有类型:
184.25、200 和 AAPL 在转换之前都只是字符。忘了这一点,得到的不是报错,而是 "184.25" * 200(文本重复 200 次)。在读取处把每一列转换一次,并按表头名称而不是想当然的位置来取值。- 用
newline=""打开;不要手工拆分或拼接 CSV 行。 csv.DictReader把行读成字典;每个单元格都是字符串。csv.writer/csv.DictWriter写入行并自动加引号。
下一节:JSON 数据,用于无法放进平面表格的嵌套记录。
实验:评分内容
- 用
read_closes按代码归组收盘价25 分 - 用
write_trades把成交保存为 CSV 文件25 分 - 用
total_by_symbol汇总每个代码的成交金额25 分 - 用
filter_rows把某个代码的行复制到新文件25 分