Python Dict and Files in Google's Python Class in Japanese

Google による Python の授業 (日本語訳)/ Google's Python Class (英語原文)

資料
日本語訳: 設定/ 入門/ 文字列/ リスト/ 整列/ 辞書とファイル / 正規表現/ ユーティリティ
英語原文: Set Up/ Introduction/ Strings/ Lists/ Sorting/ Dict and Files/ Reg. Exp./ Utilities

練習問題
日本語訳: 基本問題/ 新生児名/ 特殊なコピー/ アクセス履歴のパズル
英語原文: Basic Exercises/ Baby Names Exercise/ Copy Special Exercise/ Log Puzzle Exercise

講義映像
英語
1日目: Introduction, Strings/ Lists and Sorting/ Dicts and Files
2日目: Regular Expression/ Utilities/ Utilities urllib/ Conclusions

Python の辞書とファイル

辞書のハッシュテーブル


Python の効率的な鍵/値のハッシュテーブル構造は "dict" (辞書) と呼ばれます. 辞書の中身は中括弧に入っている鍵:値の組の列, 例えば dict = {key1:value1, key2:value2, ... } により記述できます. "空の辞書" は中身のない中括弧の組で表します.
鍵 'foo' に対する値を探すには dict['foo'] と書くように, 辞書の中の値を調べたり, 設定するには鍵括弧を使います. 鍵になるのは, 文字列, 数字, タプルで, 値には任意の型を取ることが出来ます. 他の型は鍵として正しく使える場合と使えない場合があります (文字列とタプルは不変なので, 鍵として使用できます). 辞書にない値を探すと, KeyError が起こります. 鍵が辞書にあるかどうかを確かめるには, "in", または, dict.get(key) を使うこと. dict.get(key) は 鍵 key がなければ None を, あればその値を返します. (また, get(key, not-found) により値が見つからなかった場合に返す値を 指定できます).
  ## 空の辞書 {} から始めて, 辞書を作り, 
  ## 鍵/値の組を辞書に格納するのは, 次のような方法. 
  ## dict[key] = value-for-that-key
  dict = {}
  dict['a'] = 'alpha'
  dict['g'] = 'gamma'
  dict['o'] = 'omega'

  print dict  ## {'a': 'alpha', 'o': 'omega', 'g': 'gamma'}

  print dict['a']     ## 簡単な参照, 'alpha' が返される. 
  dict['a'] = 6       ## 新しい鍵/値を辞書に入れる
  'a' in dict         ## 真
  ## print dict['z']                  ## KeyError を投げる
  if 'z' in dict: print dict['z']     ## KeyError を避ける
  print dict.get('z')  ## (KeyError の代わりに) None 

dict with keys 'a' 'o' 'g'


辞書による for の繰り返し処理において, 初期設定ではその鍵に対して 繰り返し処理を行います. 鍵の出現順序は任意になっています. dict.keys(), dict.values() というメソッドは 鍵, または, 値のリストをそのまま返します. (鍵, 値) というタプルのリストを返す items() というものもあり, これは辞書に入っているすべての鍵と値のデータを確認する効率的な方法になっています. これらのリストはすべて, sorted() 関数に渡すことが出来ます.
  ## 初期設定では, 辞書における繰り返し処理は鍵に対して行われます. 
  ## 鍵の順序はばらばらです. 
  for key in dict: print key
  ## a g o を表示します. 
  
  ## 上とまったく同じ
  for key in dict.keys(): print key

  ## .keys() のリストを得る:
  print dict.keys()  ## ['a', 'o', 'g']

  ## 同様に, 値のリストを得る .values() もあります. 
  print dict.values()  ## ['alpha', 'omega', 'gamma']

  ## 良くある場合 -- 整列した鍵の順により
  ## 鍵/値を操作する繰り返し処理
  for key in sorted(dict.keys()):
    print key, dict[key]
  
  ## .items() は辞書を (鍵, 値) のタプルで表します
  print dict.items()  ##  [('a', 'alpha'), ('o', 'omega'), ('g', 'gamma')]

  ## この繰り返し処理の書式は, .items() のタプルからなる
  ## リストに対して辞書全体を操作し, その中の1回の処理では
  ## 1つの (鍵, 値) の組を操作します. 
  for k, v in dict.items(): print k, '>', v
  ## a > alpha    o > omega     g > gamma

iterkeys(), itervalues(), iteritems() というリスト全体を作る 手間を避けるメソッドもあり, データが巨大になると良い性能を示します. しかし平易な名前を持つ keys(), values() というメソッドの方が気に入っています. Python 3000 の改定では, iterkeys() のような変種を使う必要はありません.
戦略の覚え書き: 実行効率の観点からすると, 辞書は素晴らしい道具の 1つであり, データをまとめる簡単な方法として使えるのなら, 使うべきです. 例えば, 各行が IP アドレスで始まるアクセス記録のファイルを読んで, その IP アドレスを鍵に, その IP アドレスの書いてある行を値とする辞書に データを格納することを考えます. 一旦ファイル全体を読み込めば, 任意の IP アドレスを 調べ, すぐにその行のリストを見ることが出来ます. 辞書はばらばらのデータを取り込み, 分かりやすくまとめます.

辞書の書式


% 演算子は鍵の名前を指定することで, 辞書の値を 文字列に代入する際に便利に使えます.
  hash = {}
  hash['word'] = 'garfield'
  hash['count'] = 42
  s = 'I want %(count)d copies of %(word)s' % hash  # %d は整数, %s は文字列
  # 'I want 42 copies of garfield'

削除


"del" 演算子は削除を行います. 最も簡単な場合, 変数の定義を以前から定義されていなかったかのように 削除できます. del はリストの要素や部分列を削除したり, 辞書から項目を削除するのにも使えます.
  var = 6
  del var  # var はもうありません!
  
  list = ['a', 'b', 'c', 'd']
  del list[0]     ## 初めの要素を削除
  del list[-2:]   ## 最後の 2つの要素を削除
  print list      ## ['b']

  dict = {'a':1, 'b':2, 'c':3}
  del dict['b']   ## 'b' の項目を削除
  print dict      ## {'a':1, 'c':3}

ファイル


open() 関数はファイルを開き, 通常ファイルを読み書きするのに使うファイル識別子を返します. f = open('name', 'r') というコードは, 読み取り操作を行えるように そのファイルを変数 f に開き, 終了したときに f.close() を使います. 'r' の代わりに, 書き込みには 'w' を, 追加には 'a' を使うこと. 特別な方式 'rU"' は 異なる行末記号の変換に対応する テキストファイルに対する万能な選択肢なので, 読み込んだ行末文字は常に単純な '\n' として扱われます. 標準的な for による繰り返し処理はテキストファイルに対して利用でき, そのファイルの行に対して繰り返し処理を行います (これはテキストファイルには使えますが, バイナリファイルには使えません). for による繰り返し処理は, テキストファイル中の すべての行を見るのに簡単で効率的な方法です.
  # ファイルの中身をそのまま表示する
  f = open('foo.txt', 'rU')
  for line in f:   ## ファイル中の行に対して繰り返す
    print line,    ## , をつけることで, print に行末文字を足さない.
                   ## これは 'line' が既に行末文字を含んでいるため. 
  f.close()

一度にファイル全体をメモリに収める必要がないなら, 1行ずつ読み込むのも悪くありません. もし 10ギガバイトのメモリを使わずに 10ギガバイトのファイルを読みたいときも, 1行ずつ読み込む方が手軽でしょう. f.readlines() メソッドはファイル全体をメモリに読み込み, ファイル中の各行をリストにして返します. f.read() メソッドはファイル全体を1つの文字列として読み込むので, 後で学ぶ正規表現を使うときなど, テキスト全体を一気に扱うときには便利です.
書き込みについて, f.write(string) メソッドは開いた出力ファイルへデータを書くのに 最も簡単な方法です. また, 開いたファイルに "print" を使うことも出来ますが, 書式が "print >> f, string" とわかりにくくなっています. Python 3000 では, print の書式は file= という任意の引数を使う通常の関数呼び出し の形 "print(string, file=f)" に訂正されています.

ファイルの Unicode


"codecs" モジュールを使うと Unicode のファイルを読めるようになります.
import codecs

f = codecs.open('foo.txt', 'rU', 'utf-8')
for line in f:
  # ここで line は *Unicode* の文字列です. 

ファイルへの書き込みでは, print が Unicode を十分に扱えないため, f.write() を使うこと.

練習問題における追加的な開発


Python のプログラムをつくるときに, 一度に全部を書こうとしないこと. そうではなく, "まず第一段階は単語のリストを抽出すること" といった 1つ目の目標を決めること. その目標に到達するためのコードを書き, その時点でのデータ構造を出力させた後に sys.exit(0) を実行すれば, 終わっていない部分のプログラムは 実行されません. 一旦目標のコードが出来上がったら, 次の目標に対するコードに 取り掛かります. ある状態での変数の出力結果が見ておくと, 次の状態でその変数をどう変化させればよいのかを考える参考になります. Python はとてもこのパターンに迅速に対応でき, プログラムに少し変更を加えては上手く動作するかを見るために, プログラムを実行することが出来ます. 小さく段階を踏んでプログラムを組むことで, 迅速に改善できる利点を活かせます.

練習問題: wordcount.py


文字列, リスト, 辞書, タプル, ファイルといった Python の基本道具を組み合わせて, Basic Exercises (英語原文), 基本の練習問題 (日本語訳) のまとめである wordcount.py 問題に挑戦すること.
この資料は Google の Nick Parlante によって作成されたものの翻訳です. Google による Python の授業の文章と映像は Creative Commons Attribution 2.5 ライセンスの下で利用できます.