はじめに
このシリーズの第1回では、コア言語と型システムの重要な変更点について解説しました。今回は、Python 3.0における数値、文字列、バイナリデータの基本データ型の処理を中心に説明します。
これまでの連載
PEP 237:長整数型と整数型の統合
Python 2.xには、int
とlong
の2つの整数型がありました。int
型は、マシンの「ネイティブ」ワードサイズ(現在の機種では32ビットまたは64ビット)に制限されます。そのためint
型の演算では、オーバーフローしてOverflowError例外が発生する可能性がありました(Python 2.2より前のバージョン)。これに対し、long
型はメモリ容量のみに制限され、理論的にはあらゆる整数を表現できます。
2種類の整数型が用意されていた理由は、int
型とlong
型にそれぞれ異なる特徴があったからです。int
型はハードウェアとOSで直接サポートされるため非常に効率的であり、一方、long
型は柔軟性があって開発者が値のサイズを監視する必要がありません。しかし、アーキテクチャの異なるマシン間でPythonのコンパイル済みファイルやpickle
化オブジェクトを移植する場合には、型が2種類あることで問題が発生します。
PEP-237の目的は、これら2つの型を1つの整数型に統合し、可能な場合にはより効率的なマシン整数型を使用するよう内部的に変化させることです。これは、実のところ4つのバージョンで段階的に実装され、2.2、2.3、2.4を経て3.0で完了しました。
Python 2.4以上では、例外も警告も発生させない、int
からlong
への自動昇格が既にサポートされています。Python 3.0では、単にPythonレベルでlong
型とlong
リテラルをなくしただけです。Python 3.0でlong
を使用しようとすると、次のようなエラーが発生します。
>>> long Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'long' is not defined
Python 3.0では、long
用のL
サフィックスも削除されました。現在は整数はすべてint
型です。Python 2.5では次のコードは有効ですが、
>>> 5L 5L
Python 3.0では構文エラーになります。
>>> 5L File "<stdin>", line 1 5L ^ SyntaxError: invalid syntax
Python 2.5では、次のコードはlong
オブジェクトを生成しますが、
>>> x = 5 ** 88 >>> type(x) <type 'long'> >>> x 32311742677852643549664402033982923967414535582065582275390625L
Python 3.0ではint
になります。
>>> x = 5 ** 88 >>> type(x) <class 'int'> >>> x 32311742677852643549664402033982923967414535582065582275390625
PEP 3127:整数リテラルのサポートと構文
Pythonでは以前から、整数の基数を広範にサポートしてきました。Python 2.5のint()
関数とlong()
関数は、第2引数として変換元の基数を受け取ります。この基数には、2~36の整数を指定できます。
>>> int('000111', 2) 7 >>> int('000111', 1) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: int() base must be >= 2 and <= 36 >>> int('000111', 36) 1333 TypeError: long() can't convert non-string with explicit base >>> long('555555555555555555555555555555555555555', 6) 2227915756473955677973140996095L
Python 3.0でもこの機能は維持されています(ただし、エラーメッセージでは、base
の代わりにarg 2
と示されます)。
>>> int('0001111', 2) 15 >>> int('5', 36) 5 >>> int('5', 37) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: int() arg 2 must be >= 2 and <= 36
Python 2.5では、8進と16進の整数リテラルもサポートしており、整数を指定するところでは、8進値または16進値も指定できます。8進値には0123
のように先頭に数字のゼロを付け、16進値には0x123
のように先頭に数字のゼロと文字x
またはX
を付けます。また、oct()
とhex()
という2つの関数もあります。どちらも整数を受け取り、それぞれ8進値または16進値の文字列表現を返します。次に例を示します。
>>> 010 8 >>> 010 + 8 16 >>> 0xa 10 >>> 0xa + 010 + 2 20 >>> oct(20) '024' >>> hex(20) '0x14'
Python 3.0でもこれらの機能はすべて維持されますが、1つだけ小さな変更があります。8進値のプレフィックスは、先頭に数字のゼロと文字o
またはO
を付けるように変更されました。従って、これまで0123
のように書いていたものが0O123
という表記になります。数字のゼロ1文字を付けるという以前の表記は、C言語に由来する表記です。今回の変更は、C系列の言語や8進値になじみのない開発者の混乱を防ぐ効果があります。そのような開発者は、先頭にゼロを付けても値は変わらないと誤解しやすく、例えば、書式を整えたり、インデントを揃えたりする目的で先頭にゼロを付けることで、予期しない値を設定してしまう可能性がありました。また、Python 3.0では、2進リテラルも追加されました。このように、Cの遺産から脱却することによって、整数リテラルの基数表現が統一され、基数2、8、16(2進数、8進数、16進数)のプレフィックスは、それぞれ0b
、0o
、0x
となります。
>>> 0b10 2 >>> 0o10 8 >>> 0x10 16
また、新しいbin()
関数も追加されました。これは、整数を2進文字列表現に変換します(oct()
やhex()
と同様の機能です)。
>>> bin(5) '0b101' >>> bin(0x10) '0b10000' >>> bin(0o10) '0b1000'
当然、oct()
関数でも、Python 2.5の0
プレフィックスではなく、新しい0o
プレフィックスが使用されます。
>>> oct(12) '0o14'
この変更は、全体から見れば小さな変更ですが、すっきりと洗練された、いいことずくめの解決策だと思います。新しいユーザーの障害を取り除き、過去(C言語の8進表記)のしがらみから離れ、その上、基数リテラルの表現が統一されたことで、新しい2進リテラルの追加にとっても重要な改善となっています。