2013-11-21 54 views
4

在Python腳本中,程序員可以導入readline,然後給出input()擴展能力(readline有許多其他用途)。我想在我的腳本中使用select.select()而不是input(),因爲我喜歡超時功能。但是,當readline被導入時,我無法使用input()通過readline獲得的功能。我所說的「擴展功能」的一個例子是,可以按下向上鍵並查看以前的輸入,或使用左右箭頭鍵移動內聯光標以更改輸入。Python3:selectline equavalent in select.select()

問題:如何讓select.select()具有GNU-readline特性?這甚至有可能嗎?

編輯:爲了以防萬一你好奇我想要完成什麼,我做了一個基於終端的聊天機器人(有點像Alicebot)。我希望殭屍程序感到厭倦,如果在規定的時間內沒有收到任何輸入信息,請執行其他操作。 (https://launchpad.net/neobot

回答

3

您可以使用readline模塊的readline.set_pre_input_hook([function])機制來完成此操作。

下面是一個在沒有輸入10秒後超時的示例 - 未實現的機制是禁用如果提供了輸入,則報警。

由於信號無法穿過線程,因此必須用不同的線程完成。但是,你得到的基本想法..

我爲此代碼的進步道歉,我在我的筆記本電腦上的咖啡廳,只是有點打了一起。這是python2.7代碼,但基本上應該與python3兼容 - 概念是重要的一部分。

我想你會想要在input_loop()函數開頭的某處放置報警,如果你想讓每一行輸入都有一個超時。

您還應該查看Python模塊樹中的readline.c源文件以獲取更多的建議。

#!/usr/bin/python 

import readline 
import logging 
import signal 
import os 

LOG_FILENAME = '/tmp/completer.log' 
HISTORY_FILENAME = '/tmp/completer.hist' 

logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG,) 

class YouAreTooSlow(Exception): pass 


def get_history_items(): 
    return [ readline.get_history_item(i) 
      for i in xrange(1, readline.get_current_history_length() + 1) 
      ] 

class HistoryCompleter(object): 

    def __init__(self): 
     self.matches = [] 
     return 

    def complete(self, text, state): 
     response = None 
     if state == 0: 
      history_values = get_history_items() 
      logging.debug('history: %s', history_values) 
      if text: 
       self.matches = sorted(h 
             for h in history_values 
             if h and h.startswith(text)) 
      else: 
       self.matches = [] 
      logging.debug('matches: %s', self.matches) 
     try: 
      response = self.matches[state] 
     except IndexError: 
      response = None 
     logging.debug('complete(%s, %s) => %s', 
         repr(text), state, repr(response)) 
     return response 

def input_loop(): 
    if os.path.exists(HISTORY_FILENAME): 
     readline.read_history_file(HISTORY_FILENAME) 
    print 'Max history file length:', readline.get_history_length() 
    print 'Startup history:', get_history_items() 
    try: 
     while True: 
      line = raw_input('Prompt ("stop" to quit): ') 
      if line == 'stop': 
       break 
      if line: 
       print 'Adding "%s" to the history' % line 
    finally: 
     print 'Final history:', get_history_items() 
     readline.write_history_file(HISTORY_FILENAME) 

# Register our completer function 

def slow_handler(signum, frame): 
    print 'Signal handler called with signal', signum 
    raise YouAreTooSlow() 

def pre_input_hook(): 
    signal.signal(signal.SIGALRM, slow_handler) 
    signal.alarm(10) 

readline.set_pre_input_hook(pre_input_hook) 
readline.set_completer(HistoryCompleter().complete) 

# Use the tab key for completion 
readline.parse_and_bind('tab: complete') 

# Prompt the user for text 
input_loop() 
-1

好像readline的設計擁有這種能力的考慮(link)。

備用接口可用於plain readline()。某些應用程序需要將鍵盤I/O與文件,設備或窗口系統I/O交錯,通常通過使用主循環在各種文件描述符上選擇()。爲了適應這種需求,readline也可以作爲事件循環中的「回調」函數來調用。有一些功能可以使這一切變得簡單。

但是看起來這些綁定並沒有在Python中實現。做一個快速搜索,有here誰通過使用CType加載函數調用完成POC。這並不理想,但缺乏其他選擇,也許這是你唯一的行動方針。