SSブログ

Python2 と Python3 の数値、文字列データの取り扱い [Python]

たかのりさんから回ってきました
Python3 アドベントカレンダーの6日目です

Python3 では、Python2 の経験をふまえつつ、過去との互換性にとらわれず
1. 言語としての機能の整理と強化
2. ライブラリの整理
がおこなわれました。

1. については 2.6 と 2.7 で多くの機能がバックポートされました
2. については、無意味に互換性のなくなるような変更がされてるわけではないので
既存のものは動かなくなっちゃいますが、新規に書く場合はそれほど困らない程度です

ということは、(サードパーティのライブラリの有無はさておき)すんなりと Python2 から Python3 に移行できそうなものですが、実のところ数値と文字列データの取り扱いにちょっとした変化があったおかげで、人間の脳みそ的には「ほぼ同じ=すんなり移行」とはいかないように思います。
以下に、僕が、Python2 から Python3 になったときに変わったなぁ、と思っている数値と文字列の取り扱いの違いについて書きたいと思います。

【割り算演算子'/' の結果】
Python2 では、整数同士の除算演算子 '/' では、あまりが切り捨てられましたが Python3 では浮動小数点で小数点以下も割り算がおこなわれるようになりました。
整数同士の除算で結果が整数になって余りが切り捨てられる'//' 演算子が、Python2 でも Python3 でも使えるので、整数値が必要な場合は日頃から '//' 演算子を使うようにすると良いかもしれません。

[python2]
>>> 100/3
33
>>> 100//3
33
>>>


[python3]
>>> 100/3
33.333333333333336
>>> 100//3
33
>>>


【int と long の統合】
Python2 では、 32 bit に納まる数値を int 型として、その範囲を超える整数を扱える型として long 型を持っていましたが、Python3 では、両者をまとめて数値型として扱うようになっています。
Python2 で、計算結果が32bit を超えると自動で long に変換されますが、その後(除算なので)32bit に納まっても、int 型にはなりません。関数に int を渡してるつもりが long を渡した時に「それ int じゃねえよ」って怒られないかと思うと、ちょっとうれしいです。
[python2]
>>> 100000*100000
10000000000L
>>> 100000*100000//100000
100000L


[python3]
>>> 100000*100000
10000000000
>>> 100000*100000//100000
100000


【文字列型 unicode 型、bytes 型 bytearray 型】
ここが一番大きな違いだと思います。

Python2 では、
1. 文字列型(入力された文字コードを保持)
2. unicode 文字列(常に unicode 型で保持)
という2種類の文字列型があります。
Python2.0 になった時に、 unicode 型が後付けで追加されたために、似て非なる型ができてしまったようです。バイナリデータは、1. の文字列型の中に無理矢理入れて扱っていました。

かたや Python3 では
1. 文字列型(内部的には unicode で統一的に取り扱われている)
2. bytes 型/bytearray 型(内部的にバイト列として扱われる)
の2種類になり、 2. のほうは、もはや文字列ではありません。
(bytes 型と bytearray 型は、イミュータブルかミュータブルかの違いですので、以下 バイト列の代表として bytes 型を取り上げます)

[python2]
>>> 'あいうえお'
'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a'
>>> type('あいうえお')
<type 'str'>
>>> u'あいうえお'
u'\u3042\u3044\u3046\u3048\u304a'
>>> type(u'あいうえお')
<type 'unicode'>
>>> u'あいうえお'.encode('utf-8')
'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a'
>>>


[python3]
>>> 'あいうえお'
'あいうえお'
>>> type('あいうえお')
< class 'str' >
>>> b'あいうえお'
  File "", line 1
SyntaxError: bytes can only contain ASCII literal characters.
>>> b'abcde'
b'abcde'
>>> type('abcde')
< class 'str' >
>>> type(b'abcde')
< class 'bytes' >
>>> 'あいうえお'.encode('utf-8')
b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a'
>>> b'\x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8'.decode('cp932')
'あいうえお'
>>>


【Python3 での文字列の入出力】
Python2 では、文字列が内部的にどういう encoding になっているかを意識しなくてはなりませんでした(特に日本語を取り扱う場合)。それが、Python3 になると、文字列は一貫して unicode として扱えるようになってすっきり処理できると思います。
ただ、Python2 と違い、外部との入出力で、常に外部データを取り込む時に、それがどういう encoding になっているかを気にしなくてはいけなくなりました。
(入出力だけ気にすれば、内部の処理は文字コードを気にしなくて良いとも言えます)
JVM や CLR の文字列の扱いと同じようになったんだなぁ、と思う人も多いと思います。僕はそう思いました。
典型的な例では、ファイルの読み込み時にテキストとして読む場合には、encoding を指定してあげる必要があります。
a_file = open('examples/chinese.txt', encoding='utf-8')

ここらへんの説明は、 Dive Into Python3 のファイルの取り扱いについての章がわかりやすいと思います。
http://diveintopython3-ja.rdy.jp/files.html
(この章だけでなく Dive Into Python3 は非常にわかりやすいと思います)

その他、例えば urllib で html を取得する場合は、 bytearray で取って来れるので、それを decode() で文字列に変換しないといけないみたいです。

どうでしょう?ややこしかったでしょうか?これから始めるなら Python2 か Python3か?という質問を時々見かけますが、Python2 は、これからまだ何年か現役でいそうですし、 Python2 と Python3 の違いを知ることが Python2 を知るうえでも、 Python3 を知るうえでも近道のような気もします。

ここまで見てわかる通り、Python3 の方が多少すっきり書けるような気がしなくもないですが,Python2 と Python3 を比較した場合、できることとできないことにほとんど違いはありません。現状では、ライブラリが充実している分、まだまだ Python2 の方ができることが多いと思います。そういう意味では、今すぐ Python3 で書くメリットはむしろあまりないでしょう。
しかしながら、ここに来て Python3 のサードパーティモジュールも出揃って、来年あたり Python3 を本番投入するときが来るのではないかという予感がしています。
いまのうちから、 Python3 に慣れ親しんでおいては如何でしょう。


・・・と、これで自分のエントリは終わりです。
次は、新婚で幸せいっぱいの @shimizukawa さんにお願いしたいと思います。

コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

コメント 0

コメントの受付は締め切りました

Facebook コメント

トラックバック 0