Python で Hello world!

ここしばらくは Mark Lutz 著、夏目大訳の 『初めての Python 第 3 版』 を読んでました。 とにかく分厚くて (700 ページ超) しかも内容的には同じことを繰り返したり重要でない事を長々と説明していたりであんまり楽しんで読めませんでしたが、まあ一通り Python のことはわかったかなー、という感じです。

まあ人にはオススメできない一冊ですね。。

そんなわけで基本を

というわけで Python の基本的なことでも書いておこうかと。 『初めての Python 第 3 版』 は残念ながら Python 3 にはあまり対応していませんでしたので、Python v3.1.1 documentation あたりを参考にして、Python 3 における文字列とバイト列について書いておきます。

Python 3 における文字列とバイト列の扱い

Python 3 では、文字列とバイト列が明確に区別されています。 つまり、「文字列」 というのは文字の列であってエンコーディングとは無関係であり、「エンコーディングされた文字列」 は 「バイト列」 であるとする考え方です。 Perl 5.8 以降と同じ形式ですね。

一方 Ruby では、バイト列と文字列を明確には区別せず、バイト列と文字エンコーディングの組合せで文字列を表しています。 Ruby の考え方だと、Shift_JIS エンコーディングの "\x82\xE0\x82\xB6" という String 型オブジェクトも UTF-8 エンコーディングされた "\xE3\x82\x82\xE3\x81\x98" という String 型オブジェクトも 「もじ」 という文字列を表現します。 しかし、同じ 「もじ」 という文字列を表現するにもかかわらず、それら 2 つのオブジェクトは同値だとみなされません。 (エンコーディングが異なるため。) Ruby をメインに使っていて Python の勉強をしている、という人はこの点に注意してください。

さて、Python 3 における文字列ですが、str 型のオブジェクトとなります。 単にシングルクォーテーションやダブルクォーテーションで括って文字列を記述する事で str 型オブジェクトとなります。

# -*- coding: utf-8 -*-
# ソースコードのエンコーディングを指定するために,
# ファイルの 1 行目か 2 行目に上記のような指定を入れる (以下のコードでは省略)

test_str = "文字列"
test_str.__class__ # <class 'str'>

次にバイト列ですが、bytes 型オブジェクトで表現されます。 bytes 型オブジェクトは、文字列コンテキスト (文字列を表すためにクォーテーションで囲んだ表現) の前に接頭辞 b をつけることで生成できます。

test_bytes = b"\x41\x55\x33"
test_bytes.__class__ # <class 'bytes'>

また、str 型オブジェクトをエンコード (str#encode メソッドを使用) すると bytes 型オブジェクトが返されます。 その逆に bytes 型オブジェクトをデコード (bytes#decode メソッドを使用) すると str 型オブジェクトが返されます。

test_src = "文字列"

# str 型オブジェクトを Shift_JIS でエンコードする
test_bytes = test_src.encode("shift_jis") # 引数でエンコード後のエンコーディングを指定する
test_bytes.__class__ # <class 'bytes'>

# bytes 型オブジェクトを Shift_JIS でエンコードされているとみなしてデコードする
test_str = test_bytes.decode("shift_jis") # 引数で, test_bytes のエンコーディングを指定する
test_str.__class__ # <class 'str'>

入出力

上で述べたように、Python 3 の str 型オブジェクトは文字エンコーディングとは無縁なのですが、入出力する時にはエンコードしなければなりません。 (ファイルに出力するにしても、端末上に表示するにしても、エンコードしてバイト列に変換しなければいけません。)

ですが、標準出力 (sys.stdout) の write メソッドを使って str 型オブジェクトを出力すると、ちゃんと端末上に文字が表示されるはずです。

import sys
test_str = "日本語"
sys.stdout.write( test_str )

これは、自動的にエンコードが行われているからです。 標準出力に出力する際に、OS のデフォルトエンコーディング (例えば Windows であれば CP932) などに自動的にエンコードされているのです。 標準出力 (sys.stdout) がテキストストリームであるので、このような機能があるのです。

逆に言えば、テキストストリームに bytes 型オブジェクトを出力しようとしてもそれはできません。

import sys
test_bytes = b"\x41\x42"
sys.stdout.write( test_bytes ) # テキストストリームにバイト列を出力しようとするので例外発生

print( test_bytes ) # print 関数を使えば, 自動的に str 型に変換されるので出力できる

bytes 型オブジェクトを出力するには、バイトストリームを使用しなければなりません。 以下で、ファイル入出力を例に str 型オブジェクトと bytes 型オブジェクトの入出力を見てみます。

ファイル入出力

ファイルに対して出力を行うためには、まず出力ストリームを取得します。 上で述べたように、ストリームには文字列に対応したテキストストリームとバイト列に対応したバイトストリームの 2 種類があります。 どちらのストリームを得るのかは、open 関数実行時に引数で指定します。

test_str = "文字列"
test_bytes = b"\x41\x42"

# モード指定に t を書いた場合, または t も b も書かなかった場合は
# テキストモードとなりテキストストリームが得られる
# また, 出力先の文字エンコーディングを指定できる
# (指定しなければ OS のデフォルトが使用される模様)
writer = open( "str.text", mode="wt", encoding="euc-jp" )
writer.write( test_str ) # テキストストリームは文字列の入出力のためのもの
writer.close()

# モード指定に b を書いた場合はバイナリモードとなりバイナリストリームが得られる
writer = open( "bytes.text", mode="wb" )
writer.write( test_bytes ) # バイトストリームはバイト列の入出力のためのもの
writer.close()