こんにちは、かつコーチです。
業務の現場では、Excelから出力したCSVファイルを扱う機会がとても多いです。
CSVとは「Comma-Separated Values」の略で、値をカンマ区切りで並べたシンプルなファイル形式です。
Pythonには、このCSVファイルを扱うためのcsvモジュールが標準ライブラリとして用意されています。
自分でカンマを分割するコードを書く必要はなく、csvモジュールに任せてしまうのが安全です。
この記事では、csvモジュールを使った読み書きの基本と、文字コードでハマった実体験を紹介します。
読み終える頃には、業務でよくあるCSV操作を自力でこなせるようになっているはずです。
csvモジュールの基本操作
CSVファイルを読み込む(csv.reader)
csv.readerを使うと、CSVファイルを1行ずつリストとして読み込めます。
import csv
with open("users.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader:
print(row)
# ['name', 'age', 'city']
# ['Katsu', '30', 'Tokyo']
1行目にヘッダー(項目名)が含まれている場合、最初のrowはヘッダーの配列になります。
中身を扱うときは、ヘッダー行を読み飛ばすか、後述のDictReaderを使うと便利です。
CSVファイルに書き込む(csv.writer)
書き込みにはcsv.writerを使います。
1行ずつリストで渡すwriterow()と、複数行まとめて渡すwriterows()があります。
import csv
data = [
["name", "age", "city"],
["Katsu", 30, "Tokyo"],
["Suzuki", 25, "Osaka"],
]
with open("output.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerows(data)
open()にnewline=""を指定している点に注目してください。
これを省略すると、Windows環境で行と行の間に空行が入ってしまうことがあります。
辞書形式で読み込む(DictReader)
行番号ではなく、列名(キー)でデータにアクセスしたい場合はcsv.DictReaderが便利です。
import csv
with open("users.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], row["age"])
# Katsu 30
# Suzuki 25
DictReaderはヘッダー行を自動でキーとして扱ってくれます。
列の順番を気にせず、名前でアクセスできるため、可読性の高いコードになります。
辞書形式で書き込む(DictWriter)
書き込み側にも、辞書に対応したcsv.DictWriterがあります。fieldnamesでヘッダーを指定し、writeheader()でヘッダー行を出力します。
import csv
data = [
{"name": "Katsu", "age": 30, "city": "Tokyo"},
{"name": "Suzuki", "age": 25, "city": "Osaka"},
]
with open("output.csv", "w", encoding="utf-8", newline="") as f:
fieldnames = ["name", "age", "city"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
fieldnamesに指定した順番で列が出力されます。
辞書のキーの並び順に依存しないため、意図した通りの列順にできます。
よくあるつまずきポイント・エラー対処
文字コードが原因で文字化けする
Before(つまずいたコード)
import csv
with open("users.csv", "r") as f:
reader = csv.reader(f)
for row in reader:
print(row)
私は以前、クライアントから受け取ったExcel由来のCSVファイルをこのコードで読み込みました。
すると、次のようなエラーで処理が止まりました。
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 0: invalid start byte
原因は、Excelで作成・保存したCSVファイルが、UTF-8ではなくShift_JIS(cp932)で保存されていたことでした。open()にencodingを指定していなかったため、環境依存の文字コードで読み込もうとして失敗していたのです。
After(改善したコード)
import csv
with open("users.csv", "r", encoding="cp932") as f:
reader = csv.reader(f)
for row in reader:
print(row)
Windows版Excelで保存されたCSVは、多くの場合cp932(Shift_JISの拡張)でエンコードされています。
ファイルの提供元がわからない場合は、まずutf-8で試し、エラーが出たらcp932を試すという流れが実務では現実的です。
数値が文字列として扱われる
Before(つまずいたコード)
import csv
with open("users.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
total_age = row["age"] + 10
このコードを実行すると、次のエラーが出ます。
TypeError: can only concatenate str (not "int") to str
After(改善したコード)
import csv
with open("users.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
total_age = int(row["age"]) + 10
print(total_age)
csvモジュールは、読み込んだ値をすべて文字列として返します。
数値として計算したい場合は、int()やfloat()で明示的に型変換する必要があります。
まとめ
この記事のポイント
- csvモジュールはCSVファイルの読み書きを行う標準ライブラリです
- 読み込みは
csv.reader、書き込みはcsv.writerが基本です - 列名でアクセスしたい場合は
DictReaderとDictWriterが便利です - 文字コードは
utf-8とcp932の両方を候補に入れて対処しましょう - 読み込んだ値は文字列なので、計算するときは型変換が必要です
次に読むべき記事
JSON形式のデータも扱う機会が多い方は、jsonモジュールの解説記事もあわせてご覧ください。
ファイルパスの操作に不安がある方は、osモジュールの基本記事も参考になります。
タグ: Python, 初心者向け, 標準ライブラリ