Brief Tour of the Standard Library – Part II
標準ライブラリツアーパート2です。この章でチュートリアルはほぼ終了です。頑張っていきます。次はApp Engineです。
Output Formatting
まずはじめは出力フォーマットを整えるためのモジュールです。
>>> import repr >>> repr.repr(set('supercalifragilisticexpialidocious')) "set(['a', 'c', 'd', 'e', 'f', 'g', ...])"
reprモジュールのrepr関数はたくさんの情報を「...」という省略記号を用いて表示します。面白い機能ですね。
>>> import pprint >>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta', ... 'yellow'], 'blue']]] >>> pprint.pprint(t, width=30) [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta', 'yellow'], 'blue']]]
pprintモジュールはネストなどした複雑なデータ構造をインデントや改行で分かりやすく整形してくれます。
>>> doc = """The wrap() method is just like fill() except that it returns ... a list of strings instead of one big string with newlines to separate ... the wrapped lines.""" >>> print textwrap.fill(doc, width=40) The wrap() method is just like fill() except that it returns a list of strings instead of one big string with newlines to separate the wrapped lines.
textwrapモジュールは指定された幅の中で単語が途中で切れないように改行してくれます。そして最後にlocaleモジュール。こちらはいわゆるロケールに合わせて整形してくれるモジュールです。
>>> locale.setlocale(locale.LC_ALL, 'Englis_United States. 1252') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.5/locale.py", line 478, in setlocale return _setlocale(category, locale) locale.Error: unsupported locale setting
と思ったら、あれれ?Unspported localeだって。う〜ん???と思い、いろいろ調べてみるとこのロケールはOSに依存しているようです。つまりOSがサポートしているロケールじゃないと↑のようにエラーが発生してしまいます。ちなみに私の環境で対応しているロケールはこんな感じ。
% locale -a C POSIX en_AG en_AU.utf8 en_BW.utf8 en_CA.utf8 en_DK.utf8 en_GB.utf8 en_HK.utf8 en_IE.utf8 en_IN en_NG en_NZ.utf8 en_PH.utf8 en_SG.utf8 en_US.utf8 en_ZA.utf8 en_ZW.utf8 ja_JP.utf8
???全然違うじゃん、文字列が。ということで気を取り直して再チャレンジ。
>>> locale.setlocale(locale.LC_ALL, 'ja_JP.utf8') 'ja_JP.utf8' >>> locale.format("%d", 1234567.8, grouping=True) '1,234,567' >>> conv = locale.localeconv() >>> locale.format("%s%.*f", (conv['currency_symbol'], conv['frac_digits'], x), grouping=True) '\xef\xbf\xa51,234,568'
Templating
続いてテンプレート機能を実現するためのモジュールです。これはなかなか強力です。テンプレートとなる文字列を作成しておき、後から部分部分を書き換えて利用するわけです。
>>> from string import Template >>> t = Template('${village}folk send $$10 to $cause.') >>> t.substitute(village='Nottingham', cause='the ditch fund') 'Nottinghamfolk send $10 to the ditch fund.'
↑の例では%{village}にNottingham、$causeにthe ditch fundを当てはめています。まさしくテンプレートですね。また全ての箇所を当てはめなくてもよいように作られています。
>>> t = Template('Return the $item to $owner.') >>> d = dict(item='unlanden swallow') >>> t.substitute(d) # substituteメソッドは全て埋めないと怒られますが Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.5/string.py", line 170, in substitute return self.pattern.sub(convert, self.template) File "/usr/lib/python2.5/string.py", line 160, in convert val = mapping[named] KeyError: 'owner' >>> t.safe_substitute(d) # safe_substituteメソッドなら中途半端でもOK 'Return the unlanden swallow to $owner.'
またdelimiterという変数を上書き (Override!) すれば、テンプレートを自分好みにカスタムすることが出来ます。
Working with Binary Data Record Layouts
次はちょっと不思議な (?) モジュールです。私はこういうモジュール好きです。バイナリデータのフォーマットを指定するとその通りにデータを抜き出してくれます。イメージ的にはC言語で言うと、バイナリデータを構造体にそのままキャストしてぶち込む感覚でしょうかね。チュートリアルに掲載されていたサンプルを愚直に試してみます。3つのファイルをzipでまとめて圧縮しておき、各圧縮ファイルの
- ファイル名
- CRC32値
- 圧縮サイズ
- 解凍サイズ
を出力します。まずは適当に3つのファイルを圧縮します。
% cat test1.txt This is first test file. % cat test2.txt This is second test file. % cat test3.txt This is third test file. % zip test.zip test1.txt test2.txt test3.txt adding: test1.txt (deflated 4%) adding: test2.txt (stored 0%) adding: test3.txt (stored 0%) % file test.zip test.zip: Zip archive data, at least v2.0 to extract
次にスクリプトファイルを作成します (test_unpack.py) 。
#!/usr/bin/python2.5 #! -*- coding: utf-8 -*- import struct def unpack(file): data = open(file, 'rb').read() start = 0 for i in range(3): start += 14 # ここ! fields = struct.unpack('<IIIHH', data[start:start + 16]) crc32, comp_size, uncomp_size, filename_size, extra_size = fields start += 16 filename = data[start:start + filename_size] start += filename_size extra = data[start:start + extra_size] print filename, hex(crc32), comp_size, uncomp_size start += extra_size + comp_size
unpack時の型指定ですが、
指定 | 説明 |
---|---|
リトルエンディアンであることを示す | |
I | 2バイトデータであることを示す |
H | 4バイトデータであることを示す |
です。その他の指定はこちらを参照してください。ではスクリプトを実行してみます。
>>> import test_unpack >>> test_unpack.unpack('test.zip') test1.txt 0xd01431dfL 24 25 test2.txt 0xdab9a6eeL 26 26 test3.txt 0xe8fd7e9 25 25
おぉ〜、ちゃんとunpack出来ていますね!こういうのは実際に手を動かして試してみないと分かりませんね。
Multi-threading
最後にマルチスレッドについて。まぁ今日びのプログラミング言語でスレッドを扱えないものはありませんよね。ですが、App EngineではPythonのスレッドモジュールは利用することは出来ません。
An App Engine application cannot:
http://code.google.com/intl/en/appengine/docs/python/runtime.html#The_Sandbox
...
spawn a sub-process or thread.
...
App Engineでは基本的にApp Engineが管理するスレッド (シングルスレッド!) がHTTPリクエストを処理します。個々で勝手にスレッドを起動して重い処理を走らせてしまうとApp Engine上のリソースがいたずらに消費されてしまいます。SandBoxという性質を維持することが難しくなるのわけなのです。HTTP Requestとは別のタイミングで処理をしたければ、TaskQueueを使う必要があります。