只想拿到一行行数据、又不想再装一个依赖,就用标准库的 CSV 模块。要做列运算、筛选、分组,才上 pandas。下面的例子先给能复制的答案,再解决表头、写回文件、编码,以及 Excel 那些真会让程序挂掉的怪毛病。
🎙️ 发布并录制于: ·
DictReader 把第一行当列名,后面每一行就是一个字典。打开文件时把 newline 设成空字符串,因为换行要交给 CSV 模块自己控制。编码明确写成 UTF-8,不要指望操作系统的默认值。取出来的每个值都还是文本,做算术之前先转换。
import csv
with open("users.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
print(row["name"], row["email"])
total += float(row["amount"])
# row = {"name": "Ada", "email": "[email protected]", ...}
用字段名,不要用第零列、第二列。这样文件里的列顺序变了代码还能跑,表头缺字段时会抛一个有用的 KeyError,而不是悄悄读错了一列。
普通的 csv reader 返回的是列表。只有当文件确实有一行你想跳过的表头时,才调用一次 next。做分析就用 pandas,它会把整张表读进来并推断列的类型。分号导出的文件要显式指定分隔符;表太宽、内存吃紧时,只挑需要的列。
with open("data.csv", newline="", encoding="utf-8") as f:
reader = csv.reader(f)
next(reader) # skip header, if present
for row in reader:
print(row[0], row[2])
import pandas as pd
df = pd.read_csv("users.csv")
df.head() # first 5 rows
df["amount"].sum() # typed column math
pd.read_csv("f.csv", sep=";")
pd.read_csv("f.csv", skiprows=2)
pd.read_csv("f.csv", usecols=["name", "amount"])
直接给判断标准:如果这些行只是喂给你自己的程序,标准库就够了。如果要分组、连表、筛选,或者跨列算数,pandas 才值得那份安装成本。
DictWriter 要求一开始就给出输出的列顺序。先写一次表头,再把字典写进去。Windows 下同样要保留 newline 为空字符串;漏了这一项,就是每条记录之间凭空多一个空行的常见原因。
rows = [{"name": "Ada", "score": 95}, {"name": "Lin", "score": 88}]
with open("out.csv", "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=["name", "score"])
w.writeheader()
w.writerows(rows)
别自己用逗号把值拼成一行。像 Smith, John 这样的名字需要加引号和转义,writer 会处理对,你手拼不会。
Windows 上最常见的失败是 UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d。意思是这个文件很可能是 UTF-8,Python 却按 Windows 默认编码去读了。给 open 加上 encoding 等于 utf-8。如果是 Excel 导出的文件,在第一个列名前面塞了一个看不见的标记,就改用 utf-8-sig。
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d
# fix:
open("users.csv", newline="", encoding="utf-8")
KeyError: 'name'
# if print(reader.fieldnames) shows '\ufeffname', remove the Excel BOM:
open("users.csv", newline="", encoding="utf-8-sig")
reader.fieldnames。如果第一个名字以 \ufeff 开头,换成 utf-8-sig。如果每一行都变成了一个超长字段,打开文件看看,然后设 delimiter=";",pandas 里是 sep=";"。如果 Windows 上输出多了空行,补上 newline=""。永远不要用一行字符串按逗号切分去凑合一个真实的 CSV。Smith, John 这个值加了引号就是合法的,手工切分会不声不响地把它变成两列。老老实实用解析器,然后去修它的编码或者分隔符,而不是把它换掉。