13.1. csv
--- CSV ファイルの読み書き¶
バージョン 2.3 で追加.
CSV (Comma Separated Values、カンマ区切り値列) と呼ばれる形式は、 スプレッドシートやデータベース間でのデータのインポートやエクスポートにおける最も一般的な形式です。"CSV 標準" は存在しないため、 CSV 形式はデータを読み書きする多くのアプリケーション上の操作に応じて定義されているにすぎません。標準がないということは、異なるアプリケーション によって生成されたり取り込まれたりするデータ間では、しばしば微妙な違いが発生するということを意味します。こうした違いのために、複数のデータ源から得られた CSV ファイルを処理する作業が鬱陶しいものになることがあります。とはいえ、デリミタ (delimiter) やクオート文字の 相違はあっても、全体的な形式は十分似通っているため、こうしたデータを効率的に操作し、データの読み書きにおける細々としたことをプログラマ から隠蔽するような単一のモジュールを書くことは可能です。
csv
モジュールでは、CSV 形式で書かれたテーブル状のデータを読み書きするためのクラスを実装しています。このモジュールを使うことで、プログラマは Excel で使われている CSV 形式に関して詳しい知識をもっていなくても、 "このデータを Excel で推奨されている形式で書いてください" とか、 "データを Excel で作成されたこのファイルから読み出してください" と言うことができます。プログラマはまた、他のアプリケーションが解釈できる CSV 形式を記述したり、独自の特殊な目的をもった CSV 形式を定義することができます。
csv
モジュールの reader
および writer
オブジェクトはシーケンス型を読み書きします。プログラマは DictReader
や DictWriter
クラスを使うことで、データを辞書形式で読み書きすることもできます。
注釈
このバージョンの csv
モジュールは Unicode 入力をサポートしていません。また、現在のところ、 ASCII NUL 文字に関連したいくつかの問題があります。従って、安全を期すには、全ての入力を UTF-8 または印字可能な ASCII にしなければなりません。これについては 使用例 節の例を参照してください。
参考
- PEP 305 - CSV File API
Python へのこのモジュールの追加を提案している Python 改良案 (PEP: Python Enhancement Proposal)。
13.1.1. モジュールコンテンツ¶
csv
モジュールでは以下の関数を定義しています:
-
csv.
reader
(csvfile, dialect='excel', **fmtparams)¶ 与えられた csvfile 内の行を反復処理するような reader オブジェクトを返します。 csvfile はイテレータ(iterator)プロトコル をサポートし、
next()
メソッドが呼ばれた際に常に文字列を返すような任意のオブジェクトにすることができます --- ファイルオブジェクトでも リストでも構いません。 csvfile がファイルオブジェクトの場合、ファイルオブジェクトの形式に違いがあるようなプラットフォームでは 'b' フラグを付けて開かなければなりません。オプションとして dialect パラメタを与えることができ、特定の CSV 表現形式 (dialect) 特有のパラメタの集合を定義するために使われます。 dialect パラメタはDialect
クラスのサブクラス のインスタンスか、list_dialects()
関数が返す文字列の一つにすることができます。別のオプションである fmtparams キーワード引数は、現在の表現形式における個々の書式パラメタを上書きするために与えることができます。表現形式および書式化パラメタの詳細については、 Dialect クラスと書式化パラメタ 節を参照してください。csv ファイルから読み込まれた各行は、文字列のリストとして返されます。 データ型の変換が自動的に行われることはありません。
短い利用例:
>>> import csv >>> with open('eggs.csv', 'rb') as csvfile: ... spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|') ... for row in spamreader: ... print ', '.join(row) Spam, Spam, Spam, Spam, Spam, Baked Beans Spam, Lovely Spam, Wonderful Spam
バージョン 2.5 で変更: パーサが複数行に亘るクオートされたフィールドに関して厳格になりました。以前は、クオートされたフィールドの中で終端の改行文字無しに行が終わった場合、 返されるフィールドには改行が挿入されていましたが、この振る舞いはフィールドの中に復帰文字を含むようなファイルを読むときに問題を起こしていました。そこでフィールドに改行文字を挿入せずに返すように改められました。この結果、フィールドに埋め込まれた改行文字が重要ならば、入力は改行文字を保存するような仕方で複数行に分割されるはずです。
-
csv.
writer
(csvfile, dialect='excel', **fmtparams)¶ ユーザが与えたデータをデリミタで区切られた文字列に変換し、与えられたファイルオブジェクトに書き込むための writer オブジェクトを返します。 csvfile は
write()
メソッドを持つ任意のオブジェクトです。 csvfile がファイルオブジェクトの場合、 'b' フラグが意味を持つプラットフォームでは 'b' フラグを付けて開かなければなりません。 オプションとして dialect 引数を与えることができ、利用する CSV 表現形式 (dialect) を指定することができます。 dialect パラメタはDialect
クラスのサブクラスのインスタンスか、list_dialects()
関数が返す文字列の 1 つにすることができます。 別のオプション引数である fmtparams キーワード引数は、現在の表現形式における個々の書式パラメタを上書きするために与えることができます。 dialect と書式パラメタについての詳細は、 Dialect クラスと書式化パラメタ 節を参照してください。 DB API を実装するモジュールとのインタフェースを可能な限り容易にするために、None
は空文字列として書き込まれます。 この処理は可逆な変換ではありませんが、SQL で NULL データ値を CSV にダンプする処理を、cursor.fetch*
呼び出しによって 返されたデータを前処理することなく簡単に行うことができます。 浮動小数点数は、書き出される前にrepr()
を使って文字列に変換されます。 他の非文字列データは、書き出される前にstr()
を使って文字列に変換されます。短い利用例:
import csv with open('eggs.csv', 'wb') as csvfile: spamwriter = csv.writer(csvfile, delimiter=' ', quotechar='|', quoting=csv.QUOTE_MINIMAL) spamwriter.writerow(['Spam'] * 5 + ['Baked Beans']) spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
-
csv.
register_dialect
(name, [dialect, ]**fmtparams)¶ dialect を name と関連付けます。 name は文字列か Unicode オブジェクトでなければなりません。表現形式(dialect)は
Dialect
のサブクラスを渡すか、またはキーワード引数 fmtparams 、もしくは両方で指定できますが、 キーワード引数の方が優先されます。表現形式と書式化パラメタについての詳細は、 Dialect クラスと書式化パラメタ 節を参照してください。
-
csv.
list_dialects
()¶ 登録されている全ての表現形式を返します。
-
csv.
field_size_limit
([new_limit])¶ パーサが許容する現在の最大フィールドサイズを返します。 new_limit が渡されたときは、その値が新しい上限になります。
バージョン 2.5 で追加.
csv
モジュールでは以下のクラスを定義しています:
-
class
csv.
DictReader
(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)¶ Create an object which operates like a regular reader but maps the information read into a dict whose keys are given by the optional fieldnames parameter. The fieldnames parameter is a sequence whose elements are associated with the fields of the input data in order. These elements become the keys of the resulting dictionary. If the fieldnames parameter is omitted, the values in the first row of the file f will be used as the fieldnames. If the row read has more fields than the fieldnames sequence, the remaining data is added as a sequence keyed by the value of restkey. If the row read has fewer fields than the fieldnames sequence, the remaining keys take the value of the optional restval parameter. Any other optional or keyword arguments are passed to the underlying
reader
instance.短い利用例:
>>> import csv >>> with open('names.csv') as csvfile: ... reader = csv.DictReader(csvfile) ... for row in reader: ... print(row['first_name'], row['last_name']) ... Baked Beans Lovely Spam Wonderful Spam
-
class
csv.
DictWriter
(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)¶ Create an object which operates like a regular writer but maps dictionaries onto output rows. The fieldnames parameter is a sequence of keys that identify the order in which values in the dictionary passed to the
writerow()
method are written to the file f. The optional restval parameter specifies the value to be written if the dictionary is missing a key in fieldnames. If the dictionary passed to thewriterow()
method contains a key not found in fieldnames, the optional extrasaction parameter indicates what action to take. If it is set to'raise'
aValueError
is raised. If it is set to'ignore'
, extra values in the dictionary are ignored. Any other optional or keyword arguments are passed to the underlyingwriter
instance.Note that unlike the
DictReader
class, the fieldnames parameter of theDictWriter
is not optional. Since Python'sdict
objects are not ordered, there is not enough information available to deduce the order in which the row should be written to the file f.短い利用例:
import csv with open('names.csv', 'w') as csvfile: fieldnames = ['first_name', 'last_name'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'}) writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'}) writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})
-
class
csv.
Dialect
¶ Dialect
クラスはコンテナクラスで、基本的な用途としては、その属性を特定のreader
やwriter
インスタンスのパラメタを定義するために用います。
-
class
csv.
excel
¶ excel
クラスは Excel で生成される CSV ファイルの通常のプロパティを定義します。これは'excel'
という名前の dialect として登録されています。
-
class
csv.
excel_tab
¶ excel_tab
クラスは Excel で生成されるタブ分割ファイルの通常のプロパティを定義します。これは'excel-tab'
という名前の dialect として登録されています。
-
class
csv.
Sniffer
¶ Sniffer
クラスは CSV ファイルの書式を推理するために用いられるクラスです。Sniffer
クラスではメソッドを二つ提供しています:
Sniffer
の利用例:
with open('example.csv', 'rb') as csvfile:
dialect = csv.Sniffer().sniff(csvfile.read(1024))
csvfile.seek(0)
reader = csv.reader(csvfile, dialect)
# ... process CSV file contents here ...
csv
モジュールでは以下の定数を定義しています:
-
csv.
QUOTE_MINIMAL
¶ writer
オブジェクトに対し、 delimiter 、 quotechar または lineterminator に含まれる任意の文字のような特別な文字を含むフィールドだけをクオートするように指示します。
-
csv.
QUOTE_NONNUMERIC
¶ writer
オブジェクトに対し、全ての非数値フィールドをクオートするように指示します。reader
に対しては、クオートされていない全てのフィールドを float 型に変換するよう指示します。
-
csv.
QUOTE_NONE
¶ writer
オブジェクトに対し、フィールドを決してクオートしないように指示します。現在の delimiter が出力データ中に現れた場合、現在設定されている escapechar 文字が前に付けられます。 escapechar がセットされていない場合、エスケープが必要な文字に遭遇した writer はError
を送出します。reader
に対しては、クオート文字の特別扱いをしないように指示します。
csv
モジュールでは以下の例外を定義しています:
-
exception
csv.
Error
¶ 全ての関数において、エラーが検出された際に送出される例外です。
13.1.2. Dialect クラスと書式化パラメタ¶
レコードに対する入出力形式の指定をより簡単にするために、特定の書式化パラメタは表現形式 (dialect) にまとめてグループ化されます。表現形式は Dialect
クラスのサブクラスで、様々なクラス特有のメソッドと、 validate()
メソッドを一つ持っています。 reader
または writer
オブジェクトを生成するとき、プログラマは文字列または Dialect
クラスのサブクラスを表現形式パラメタとして渡さなければなりません。さらに、 dialect パラメタの代りに、プログラマは上で定義されている属性と同じ名前を持つ個々の書式化パラメタを Dialect
クラスに指定することができます。
Dialect は以下の属性をサポートしています:
-
Dialect.
delimiter
¶ フィールド間を分割するのに用いられる 1 文字からなる文字列です。デフォルトでは
','
です。
-
Dialect.
doublequote
¶ フィールド内に現れた quotechar のインスタンスで、クオートではないその文字自身でなければならない文字をどのようにクオートするかを制御します。
True
の場合、この文字は二重化されます。False
の場合、 escapechar は quotechar の前に置かれます。デフォルトではTrue
です。出力においては、 doublequote が
False
で escapechar がセットされていない場合、フィールド内に quotechar が現れるとError
が送出されます。
-
Dialect.
escapechar
¶ writer が、 quoting が
QUOTE_NONE
に設定されている場合に delimiter をエスケープするため、および、 doublequote がFalse
の場合に quotechar をエスケープするために用いられる、 1 文字からなる文字列です。読み込み時には escapechar はそれに引き続く文字の特別な意味を取り除きます。デフォルトではNone
で、エスケープを行ないません。
-
Dialect.
lineterminator
¶ writer
が作り出す各行を終端する際に用いられる文字列です。デフォルトでは'\r\n'
です。注釈
reader
は'\r'
または'\n'
のどちらかを行末と認識するようにハードコードされており、 lineterminator を無視します。この振る舞いは将来変更されるかもしれません。
-
Dialect.
quotechar
¶ delimiter や quotechar といった特殊文字を含むか、改行文字を含むフィールドをクオートする際に用いられる 1 文字からなる文字列です。デフォルトでは
'"'
です。
-
Dialect.
quoting
¶ クオートがいつ writer によって生成されるか、また reader によって認識されるかを制御します。
QUOTE_*
定数のいずれか (モジュールコンテンツ 節参照) をとることができ、デフォルトではQUOTE_MINIMAL
です。
13.1.3. reader オブジェクト¶
reader オブジェクト(DictReader
インスタンス、および reader()
関数によって返されたオブジェクト) は、以下の public なメソッドを持っています:
-
csvreader.
next
()¶ reader の反復可能なオブジェクトから、現在の表現形式に基づいて次の行を解析して返します。
reader オブジェクトには以下の公開属性があります:
-
csvreader.
dialect
¶ パーサで使われる表現形式の読み取り専用の記述です。
-
csvreader.
line_num
¶ ソースイテレータから読んだ行数です。この数は返されるレコードの数とは、レコードが複数行に亘ることがあるので、一致しません。
バージョン 2.5 で追加.
DictReader オブジェクトは、以下の public な属性を持っています:
-
csvreader.
fieldnames
¶ オブジェクトを生成するときに渡されなかった場合、この属性は最初のアクセス時か、ファイルから最初のレコードを読み出したときに初期化されます。
バージョン 2.6 で変更.
13.1.4. writer オブジェクト¶
Writer
オブジェクト (DictWriter
インスタンス、および writer()
関数によって返されたオブジェクト) は、以下の public なメソッドを持っています: row には、 Writer
オブジェクトの場合には文字列か数値のシーケンスを指定し、 DictWriter
オブジェクトの場合はフィールド名をキーとして対応する文字列か数値を格納した辞書オブジェクトを指定します(数値は str()
で変換されます)。複素数を出力する場合、値をかっこで囲んで出力します。このため、CSV ファイルを読み込むアプリケーションで(そのアプリケーションが複素数をサポートしていたとしても)問題が発生する場合があります。
-
csvwriter.
writerow
(row)¶ row パラメタを現在の表現形式に基づいて書式化し、 writer のファイルオブジェクトに書き込みます。
-
csvwriter.
writerows
(rows)¶ rows 引数 (上で解説した row オブジェクトのイテラブル) の全ての要素を現在の表現形式に基づいて書式化し、writer のファイルオブジェクトに書き込みます。
writer オブジェクトには以下の公開属性があります:
-
csvwriter.
dialect
¶ writer で使われる表現形式の読み取り専用の記述です。
DictWriter のオブジェクトは以下の public メソッドを持っています:
-
DictWriter.
writeheader
()¶ (コンストラクタで指定された)フィールド名の行を出力します。
バージョン 2.7 で追加.
13.1.5. 使用例¶
最も簡単な CSV ファイル読み込みの例です:
import csv
with open('some.csv', 'rb') as f:
reader = csv.reader(f)
for row in reader:
print row
別の書式での読み込み:
import csv
with open('passwd', 'rb') as f:
reader = csv.reader(f, delimiter=':', quoting=csv.QUOTE_NONE)
for row in reader:
print row
上に対して、単純な書き込みのプログラム例は以下のようになります。
import csv
with open('some.csv', 'wb') as f:
writer = csv.writer(f)
writer.writerows(someiterable)
新しい表現形式の登録:
import csv
csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
with open('passwd', 'rb') as f:
reader = csv.reader(f, 'unixpwd')
もう少し手の込んだ reader の使い方 --- エラーを捉えてレポートします。
import csv, sys
filename = 'some.csv'
with open(filename, 'rb') as f:
reader = csv.reader(f)
try:
for row in reader:
print row
except csv.Error as e:
sys.exit('file %s, line %d: %s' % (filename, reader.line_num, e))
このモジュールは文字列の解析は直接サポートしませんが、簡単にできます。
import csv
for row in csv.reader(['one,two,three']):
print row
csv
モジュールは直接は Unicode の読み書きをサポートしませんが、 ASCII NUL 文字に関わる問題のために8ビットクリーンに書き込みます。ですから、NUL を使う UTF-16 のようなエンコーディングを避ける限り エンコード・デコードを行なう関数やクラスを書くことができます。 UTF-8 がお勧めです。
以下の unicode_csv_reader()
は Unicode の CSV データ (Unicode 文字列のリスト)を扱うための csv.reader
をラップするジェネレータ(generator)です。 utf_8_encoder()
は一度に 1 文字列(または行) ずつ Unicode 文字列を UTF-8 としてエンコードするジェネレータです。エンコードされた文字列は CSV reader により分解され、 unicode_csv_reader()
が UTF-8 エンコードの分解された文字列をデコードして Unicode に戻します。
import csv
def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
# csv.py doesn't do Unicode; encode temporarily as UTF-8:
csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
dialect=dialect, **kwargs)
for row in csv_reader:
# decode UTF-8 back to Unicode, cell by cell:
yield [unicode(cell, 'utf-8') for cell in row]
def utf_8_encoder(unicode_csv_data):
for line in unicode_csv_data:
yield line.encode('utf-8')
その他のエンコーディングには以下の UnicodeReader
クラスと UnicodeWriter
クラスが使えます。二つのクラスは encoding パラメータをコンストラクタで取り、本物の reader や writer に渡されるデータが UTF-8 でエンコードされていることを保証します。
import csv, codecs, cStringIO
class UTF8Recoder:
"""
Iterator that reads an encoded stream and reencodes the input to UTF-8
"""
def __init__(self, f, encoding):
self.reader = codecs.getreader(encoding)(f)
def __iter__(self):
return self
def next(self):
return self.reader.next().encode("utf-8")
class UnicodeReader:
"""
A CSV reader which will iterate over lines in the CSV file "f",
which is encoded in the given encoding.
"""
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
f = UTF8Recoder(f, encoding)
self.reader = csv.reader(f, dialect=dialect, **kwds)
def next(self):
row = self.reader.next()
return [unicode(s, "utf-8") for s in row]
def __iter__(self):
return self
class UnicodeWriter:
"""
A CSV writer which will write rows to CSV file "f",
which is encoded in the given encoding.
"""
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
# Redirect output to a queue
self.queue = cStringIO.StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, row):
self.writer.writerow([s.encode("utf-8") for s in row])
# Fetch UTF-8 output from the queue ...
data = self.queue.getvalue()
data = data.decode("utf-8")
# ... and reencode it into the target encoding
data = self.encoder.encode(data)
# write to the target stream
self.stream.write(data)
# empty queue
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)