Pythonのinput関数による入力中に矢印キーやバックスペースの挙動がおかしい問題について
Pythonにはinputという組み込み関数がある。これは、ユーザからの入力を受け付ける関数である。
user_input = input("入力してください: ")
以上を実行すると、ターミナルに入力してください: と表示され、入力待ちの状態になる。
そして、Enterを押すとそれまでに入力した内容が確定され、user_inputに格納される。
簡易的な入力処理を実装する上で、便利な関数である。
しかしこのinput関数であるが、簡易的な処理だけあって、かなり機能は貧弱なものとなっている。
例えば、矢印キーが効かない。”abcde”と入力し、Enterを押す前に最初の文字”a”を”z”に修正しようとして左矢印キーを押すと、
カーソルが左に動くのではなく、^[[Dという入力がなされる。
また、これは環境に依存するようだが、日本語を入力するとバックスペースによる文字の削除がうまくできないという問題も起こる。 筆者の環境では、日本語(全角文字)を入力した直後にバックスペースを押すと、入力した文字が削除されるとともに、 「全角ではなく半角の分だけ」カーソルが戻る、という現象が起こった。調査の結果、この現象はmacOSで起こりやすいようだ。
これらの問題を解決する一番簡単な方法は、import readlineをinput関数の前に挿入することである。
import readline
user_input = input("入力してください: ")
これだけで、上で挙げた問題点は全て解消する。input関数がreadlineの機能を使ったものに置き換わるためだ。
readlineモジュールを用いた方法は、既存のコードにおいてinputを呼び出している部分に一切手を加える必要がないことが、大きな利点である。
欠点は、import readlineが見かけ上「インポートしたのに使われていないモジュール」となってしまうため、
Linterが警告を出す場合があることくらいだろうか。
もう一つの選択肢として、prompt-toolkitという外部パッケージを使うという方法もある。
このパッケージ内のpromptという関数は、このinput関数の高機能版といった位置付けのものである。
from prompt_toolkit import prompt
user_input = prompt("入力してください: ")
これもまた、上で示したinputの例と同じような挙動となる。
prompt関数の方は色々なオプションを指定することができて、たとえば複数行の入力を受け付けるなどといった機能がある。
かなり機能豊富であるが、inputとは違い「キーボードからの入力」に特化しており、
「リダイレクトされているかもしれない標準入力」からの入力は想定していないと思われる。
実際、標準入力がリダイレクトされているとWarning: Input is not a terminal (fd=0)という警告を発する。