便利なOrderedDict

昨日のエントリで辞書のkeyがソートされないようにしたいと書いたのですがOrderedDictという順序付辞書を使うといいようです。
Pythonの辞書をfor in文でループすると処理される順番は処理系まかせなのですが、OrderedDictは作成された順が維持されます。

このOrderedDictの素晴らしいところは通常の辞書と完全に同じ方法で値を設定できるところですね。(初期化時に値を設定する場合以外)

from collections import OrderedDict

とインポートしておけば

a = {}

a = OrderedDict()

と書き変えるだけでそれ以外の部分を一切いじることなく順序付辞書に変更できます。

oDict = OrderedDict([('a','ABC')])
nDict = {'a':'ABC'}

print (oDict == nDict) #True

これがTrueになるのが若干気持ち悪くないこともないですがどうも意図的な設計らしく、これも他の部分をいじることなく取替え可能にするためかもしれません。
欠点はPython2.6以前では標準でサポートされていないことですが2.4以降であればモジュールを用意することで対応できるようです。

昨日意味が分からないまま書いていた"ensure_ascii=False"については

If ensure_ascii is False (default: True), then some chunks written to fp may be unicode instances, subject to normal Python str to unicode coercion rules. Unless fp.write() explicitly understands unicode (as in codecs.getwriter()) this is likely to cause an error.
(もしensure_acdiiがFalse(デフォルトはTrue)ならば、出力されるデータの一部がunicodeインスタンスでもさしつかえありません、それらは通常のPython文字列からunicodeへの自動変換と同じルールに従って扱われます。出力先の書き込みメソッドが明確にunicodeを解釈しない場合(例えばcodecs.getwriter())、これがエラーの原因となるでしょう。)

http://docs.python.org/library/json.html

つまりファイルへの出力の場合はこれをFalseにしとけばunicodeを正しく出力できるということのようです。

その他細部の変更を加えて昨日のCSVJSONに変換するプログラムは下のようになりました。

# coding: shift_jis
#CSVを読み込んでJSON化する

import sys
import json
import codecs
from collections import OrderedDict

if sys.argv[1][-4:] != ".csv":
  csvFileName = sys.argv[1] + ".csv"
else:
  csvFileName = sys.argv[1]
  

#読み出しで開く
csvFile = open(csvFileName,'r')

#行のリストを作成
eachLine = []

for line in csvFile:
  eachLine.append(line.replace("\n",""))

#ファイル閉じる
csvFile.close()

eachPart = [""] * len(eachLine)

#各行をカンマで分割
for i in range(len(eachLine)):
  eachPart[i] = eachLine[i].split(',')
  
#キーのリスト
keyList = eachPart.pop(0)

#dictのリストを作る
eachDict = [""] * len(eachPart)

for i in range(len(eachPart)):
  eachDict[i] = OrderedDict()
  for j in range(len(keyList)):
    eachDict[i][keyList[j]] = unicode(eachPart[i][j] , "shift_jis")
    
#書きこむファイル作製
jsonFileName = csvFileName.replace('.csv','.json')

jsonFile = codecs.open(jsonFileName,"w","utf-8")

#JSON出力
json.dump(eachDict, jsonFile, ensure_ascii=False)

実行結果は

[{"name": "男の子", "age": "20", "sex": "male"}, {"name": "女性", "age": "25", "sex": "female"}]

目標どおりの形になりました。