目次
Pythonで対話的UIを実装したいときはreadlineモジュールを使おう
始めに
たまに、Pythonで独自にインタラクティブなインターフェースを実装する必要に駆られる場合があると思います。こういうユーザーの入力を捕らえてしまうデザインパターンはCaptive User Interfaceと言われていて、本当はUnix哲学的によくないとされています。
Avoid captive user interfaces. A program which prevents to user using any other commands for the duration “captures” the user and prevents him from taking advantage of other commands. A program should be usable in many modalities to maximise its usefulness.
Unix Design Philosophy . https://wiki.c2.com/?UnixDesignPhilosophy
しかし、どうしてもという場合は、input()
関数を使って以下のようなコードを書くと思います。
while True:
s = input("what do you want me to echo? > ")
print(f"me: {s}".format(s))
このコードの問題は、入力時にカーソルを移動しようとしたり、故意にメタ文字を入れようとすると、当たり前のように入ってしまうことです。せめて「カーソル移動ができたらな」と思いませんか?
./test.py
# what do you want me to echo? > ^A^B^E^F^G^[[C^[[D^[[D^[[C^[[D^[[C
GNU Readlineを使おう
こうした場合を想定して、なんとPythonにはポートされたGNU Readlineのライブラリがデフォルトで備わっています。これを使用すると、入力時にBashやEmacsのキーバインディングをそのまま利用できるだけでなく、コマンド履歴も実装することもできてこの上なく便利です。
たとえば、^[b (Alt-B)を押すと一単語だけ元に戻れたり、^A
(Ctrl-A)で文頭、^E
(Ctrl-E)で文末にジャンプできたりします。そのほかのキーバインディングはBash ReferencesのReadline Interaction節に網羅的に書いてあるので、ぜひ読んでみてください。また、カッコ内のキーは.inputrc
によって変えることもできます。
https://tiswww.cwru.edu/php/chet/readline/rluserman.html#Readline-Init-File
プログラムを改良する
さて、先ほどのコマンドを改良してみましょう。以下の公式リファレンスの通りに実装しただけなので、あまり面白くないですが、追加のモジュールを少し読みこんで追記するだけですぐにinput()
関数で使えます。
https://docs.python.org/3/library/readline.html
import atexit
import os
import readline
histfile = os.path.join(os.path.expanduser("~"), ".python_history")
try:
readline.read_history_file(histfile)
readline.set_history_length(1000)
except FileNotFoundError:
pass
atexit.register(readline.write_history_file, histfile)
while True:
s = input("what do you want me to echo? > ")
print(f"me: {s}".format(s))
おわりに
PythonとGNU周りのソフトウェア資産はすごいと思いました(小並感)
コメント
コメントはありません。