IPythonでunicodeリテラルを使う
IPythonとは
IPythonとは、Pythonistaの中で絶大な人気を誇るインタラクティブシェルです。
Pythonはもともとインタラクティブシェルを内蔵しているのですが、 IPythonには内蔵のインタラクティブシェルと比べて多くの利点があります。いくつか挙げてみます。
動的補完
変数名などを途中まで入力した状態でTABキーを押すと、残りを補完してくれます。 候補が複数ある時は候補一覧を表示してくれます。
シンタックスハイライト
プロンプトなどに色がつきます。ちょっとうれしいです。
通常のシェルとしても利用可能
IPythonの中で、lsでファイル一覧を見たり、cdでカレントディレクトリを移動したりできます。 !vim のようにエクスクラメーションマークに続いてコマンド名を入力することで、コマンドの実行もできます。 さらに、コマンドの出力がPythonの変数に格納され、Pythonから利用可能になります。Unixの大量のコマンドを使いこなせなかったり、Windowsでコマンドが少ないことが不満だったりするときに重宝します。
よく使う機能を省略形で記述可能
help(o) の代わりに o? でそのオブジェクトのドキュメントが読めます。
func(a, b) の代わりに func a b で関数呼び出しが可能です。
エディタと連携可能
ed foo.pyのようにすることで、foo.pyを外部エディタで開いて編集できます。 そしてエディタを閉じると、自動的にそのファイルがevalされます。 この機能を使うと、エディタで関数を書く→IPython上で動作を確認する→エディタで関数を修正する、というサイクルでサクサク開発できます。 これに馴れてしまうと、IDEが欲しいと思わなくなります。
IPythonでUnicodeリテラルを使う
IPython 0.9.1 でUnicodeリテラルを使おうとすると、次のような問題がありました
$ python Python 2.5.2 (r252:60911, Oct 5 2008, 19:24:49) [GCC 4.3.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> u"あ" u'\u3042' >>> $ ipython Python 2.5.2 (r252:60911, Oct 5 2008, 19:24:49) Type "copyright", "credits" or "license" for more information. IPython 0.9.1 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object'. ?object also works, ?? prints more. In [1]: u"あ" Out[1]: u'\xe3\x81\x82'
コンソールはUTF-8なので"あ" は3byteになっているのですが、それぞれのbyteを一文字と認識してUnicode文字に変換されています。
この問題を追ってみたところ、IPythonがPythonの組み込み関数 compile() を呼び出すときに、文字列をエンコードしてしまっているのに気づきました。
compile() の動作を調べて見たところ
>>> c = compile("""u'あ'""", "foo.py", 'single')
>>> c.co_consts
(u'\xe3\x81\x82', None)
>>> c = compile(u"""u'あ'""", "foo.py", "single")
>>> c.co_consts
(u'\u3042', None)
ビンゴです。
ということで、IPython/iplib.py に次の修正をすることで、IPythonでUnicodeリテラルが気持ちよく使えるようになります
--- iplib.py.old 2009-03-13 15:42:33.000000000 +0900
+++ iplib.py 2009-03-13 15:42:58.000000000 +0900
@@ -2019,9 +2019,9 @@
# this allows execution of indented pasted code. It is tempting
# to add '\n' at the end of source to run commands like ' a=1'
# directly, but this fails for more complicated scenarios
- source=source.encode(self.stdin_encoding)
- if source[:1] in [' ', '\t']:
- source = 'if 1:\n%s' % source
+ #source=source.encode(self.stdin_encoding)
+ if source[:1] in [u' ', u'\t']:
+ source = u'if 1:\n%s' % source
try:
code = self.compile(source,filename,symbol)
Windows (Python 2.6.1, IPython 0.9.1) でもうまく動くか確認して見ました
In [1]: u"あ" Out[1]: u'\u3042' In [2]: u"ソ" Out[2]: u'\u30bd'
バッチリです
