Google app engineと文字コード

→にも書いていますが当面の目標はGoogle app engineで何かしら作る事なのでSDKをダウンロードしてローカルで色々書いてみたりしています。

基本の使い方についてはgoogleのページで説明されているのですがこれらは英語のチュートリアルをそのまま訳したもののようで日本語の扱いについての説明がほとんどなく、サンプルコードもすべてascii文字しかでてきません。そのため日本語の扱いについてはネットで情報を収集しながら書いていたのですがそれらをここでまとめてみたいと思います。

まず一番基本のHello worldなのですがチュートリアルには

print 'Content-Type: text/plain'
print ''
print 'Hello, world!'

となっていますが、これをそのまま日本語にして

# coding: utf-8

print 'Content-Type: text/plain'
print ''
print 'こんにちは'

とし、ブラウザで表示するとFirefoxでは正しく表示されますがChromeでは文字化けします。これはutf-8で書かれている"こんにちは"に対してブラウザがどのような文字コードでそれを解釈すればよいかが指示されていないためで、ヘッダに文字コードを指定して

# coding: utf-8

print 'Content-Type: text/plain; charset=utf-8'  #この行はhttpヘッダ
print ''
print 'こんにちは'

とすれば文字化けしなくなります。
普段Windowsコマンドプロンプトpythonのコードを動かしているとUnicodeが文字化けせずに出力することができるため、つい

print 'Content-Type: text/plain'
print ''
print u'こんにちは'

というようにUnicodeオブジェクトを出力すれば文字化けを防げると勘違いしてしまう(私はしてました)のですが、そもそもコマンドプロンプトUnicodeを正しく表示できるのはそれを暗黙のうちにShift_JISに変換してくれているから(と思う)であってGoogle app engineは変換してくれません。上のようなUnicodeオブジェクトの出力はエラーになります。
そのためUnicode文字列を出力するには

print 'Content-Type: text/plain; charset=utf-8'  #ブラウザに今から送るのはutf-8で解釈するように指示して
print ''
print u'こんにちは'.encode("utf-8")                #明示的にutf-8にエンコードしてから送る

のように書くとうまくいきます。
この原則さえ守れば次のように、ソースコードutf-8で書いて、処理中は文字列をUnicodeとして扱い、ブラウザにはShift-JISで送るというようなこともできます。

# coding: utf-8

a = u'ゴチャゴチャコード'
    
print 'Content-Type: text/plain; charset=shift_jis'
print ''
print a.encode("shift_jis")

ただし毎回文字列をエンコードするのはめんどうですしバグの元にもなりそうなので実際にはソースコードutf-8で書くならばブラウザにもutf-8で解釈するように指示し、出力はバイト列で行うというのが普通だろうと思います。

# coding: utf-8

a = 'たぶん普通のコード'
    
print 'Content-Type: text/plain; charset=utf-8'  #ブラウザにutf-8で解釈するよう指示
print ''
print a           #ソースがutf-8なのでこれはutf-8で正しく解釈できるバイト列

つまり出力の際は

というようにすれば文字化けは防げると思います。