readline — GNU readline 介面


readline 模組定義了許多函式,以便於從 Python 直譯器中進行補全和歷史檔案的讀寫。這個模組可以直接使用,也可以透過 rlcompleter 模組使用,後者支援互動式提示符下的 Python 識別符號補全。使用此模組進行的設定會影響直譯器的互動式提示符和內建 input() 函式提供的提示符的行為。

Readline 鍵繫結可以透過初始化檔案配置,通常是您的主目錄中的 .inputrc。有關該檔案格式和允許的結構以及 Readline 庫功能的常規資訊,請參閱 GNU Readline 手冊中的 Readline 初始化檔案

可用性: 非 Android、非 iOS、非 WASI。

該模組在移動平臺WebAssembly 平臺上不受支援。

備註

底層 Readline 庫 API 可以由 editline (libedit) 庫而非 GNU readline 實現。在 macOS 上,readline 模組會在執行時檢測正在使用的庫。

editline 的配置檔案與 GNU readline 不同。如果您以程式設計方式載入配置字串,可以使用 backend 來確定正在使用哪個庫。

如果您在 macOS 上使用 editline/libedit readline 模擬,則位於您的主目錄中的初始化檔名為 .editrc。例如,~/.editrc 中的以下內容將開啟 *vi* 鍵繫結和 TAB 補全

python:bind -v
python:bind ^I rl_complete

另請注意,不同的庫可能使用不同的歷史檔案格式。切換底層庫時,現有歷史檔案可能會變得不可用。

readline.backend

正在使用的底層 Readline 庫的名稱,可以是 "readline""editline"

在 3.13 版本加入。

初始化檔案

以下函式與初始化檔案和使用者配置相關

readline.parse_and_bind(string)

執行在 *string* 引數中提供的初始化行。這會呼叫底層庫中的 rl_parse_and_bind()

readline.read_init_file([filename])

執行 readline 初始化檔案。預設檔名為上次使用的檔名。這會呼叫底層庫中的 rl_read_init_file()。如果給定檔名,則會引發一個 審計事件 open,檔名為該檔名;否則,檔名為 "<readline_init_file>",無論庫解析到哪個檔案。

3.14 版本新增: 增加了審計事件。

行緩衝區

以下函式對行緩衝區進行操作

readline.get_line_buffer()

返回行緩衝區的當前內容(底層庫中的 rl_line_buffer)。

readline.insert_text(string)

在游標位置插入文字到行緩衝區中。這會呼叫底層庫中的 rl_insert_text(),但忽略返回值。

readline.redisplay()

更改螢幕顯示以反映行緩衝區的當前內容。這會呼叫底層庫中的 rl_redisplay()

歷史檔案

以下函式對歷史檔案進行操作

readline.read_history_file([filename])

載入 readline 歷史檔案,並將其附加到歷史列表中。預設檔名為 ~/.history。這會呼叫底層庫中的 read_history(),如果給定檔名,則會引發一個 審計事件 open,檔名為該檔名;否則,檔名為 "~/.history"

3.14 版本新增: 增加了審計事件。

readline.write_history_file([filename])

將歷史列表儲存到 readline 歷史檔案,覆蓋任何現有檔案。預設檔名為 ~/.history。這會呼叫底層庫中的 write_history(),如果給定檔名,則會引發一個 審計事件 open,檔名為該檔名;否則,檔名為 "~/.history"

3.14 版本新增: 增加了審計事件。

readline.append_history_file(nelements[, filename])

將歷史記錄中的最後 *nelements* 項附加到檔案中。預設檔名為 ~/.history。檔案必須已經存在。這會呼叫底層庫中的 append_history()。此函式僅在 Python 編譯的庫版本支援它時才存在。如果給定檔名,則會引發一個 審計事件 open,檔名為該檔名;否則,檔名為 "~/.history"

在 3.5 版本加入。

3.14 版本新增: 增加了審計事件。

readline.get_history_length()
readline.set_history_length(length)

設定或返回要儲存在歷史檔案中的所需行數。write_history_file() 函式使用此值透過呼叫底層庫中的 history_truncate_file() 來截斷歷史檔案。負值表示歷史檔案大小無限制。

歷史列表

以下函式對全域性歷史列表進行操作

readline.clear_history()

清除當前歷史記錄。這會呼叫底層庫中的 clear_history()。此 Python 函式僅在 Python 編譯的庫版本支援它時才存在。

readline.get_current_history_length()

返回歷史記錄中當前專案的數量。(這與 get_history_length() 不同,後者返回將寫入歷史檔案的最大行數。)

readline.get_history_item(index)

返回 *index* 處歷史專案的當前內容。專案索引是基於一的。這會呼叫底層庫中的 history_get()

readline.remove_history_item(pos)

從歷史記錄中刪除由其位置指定的歷史專案。位置是基於零的。這會呼叫底層庫中的 remove_history()

readline.replace_history_item(pos, line)

用 *line* 替換由其位置指定的歷史專案。位置是基於零的。這會呼叫底層庫中的 replace_history_entry()

readline.add_history(line)

將 *line* 附加到歷史緩衝區,就像它是最後輸入的行一樣。這會呼叫底層庫中的 add_history()

readline.set_auto_history(enabled)

啟用或停用透過 readline 讀取輸入時自動呼叫 add_history()。*enabled* 引數應該是一個布林值,當為 true 時啟用自動歷史記錄,當為 false 時停用自動歷史記錄。

在 3.6 版本加入。

CPython 實現細節: 自動歷史記錄預設啟用,並且對此的更改不會在多次會話之間持續存在。

啟動鉤子

readline.set_startup_hook([function])

設定或移除由底層庫的 rl_startup_hook 回撥呼叫的函式。如果指定了 *function*,它將用作新的鉤子函式;如果省略或為 None,則移除任何已安裝的函式。鉤子在 readline 列印第一個提示符之前不帶引數地呼叫。

readline.set_pre_input_hook([function])

設定或移除由底層庫的 rl_pre_input_hook 回撥呼叫的函式。如果指定了 *function*,它將用作新的鉤子函式;如果省略或為 None,則移除任何已安裝的函式。鉤子在列印第一個提示符之後且在 readline 開始讀取輸入字元之前不帶引數地呼叫。此函式僅在 Python 編譯的庫版本支援它時才存在。

補全

以下函式與實現自定義單詞補全函式有關。這通常透過 Tab 鍵操作,可以建議並自動補全正在輸入的單詞。預設情況下,Readline 設定為由 rlcompleter 用於為互動式直譯器補全 Python 識別符號。如果 readline 模組要與自定義補全器一起使用,則應設定不同的單詞分隔符。

readline.set_completer([function])

設定或移除補全函式。如果指定了 *function*,它將用作新的補全函式;如果省略或為 None,則移除任何已安裝的補全函式。補全函式以 function(text, state) 的形式呼叫,其中 *state* 為 0, 1, 2, …,直到它返回一個非字串值。它應該返回以 *text* 開頭的下一個可能的補全。

已安裝的補全函式由傳遞給底層庫中的 rl_completion_matches() 的 *entry_func* 回撥呼叫。*text* 字串來自底層庫的 rl_attempted_completion_function 回撥的第一個引數。

readline.get_completer()

獲取補全函式,如果沒有設定補全函式則返回 None

readline.get_completion_type()

獲取正在嘗試的補全型別。這會將底層庫中的 rl_completion_type 變數作為整數返回。

readline.get_begidx()
readline.get_endidx()

獲取補全範圍的起始或結束索引。這些索引是傳遞給底層庫的 rl_attempted_completion_function 回撥的 *start* 和 *end* 引數。在相同的輸入編輯場景中,這些值可能因底層 C readline 實現而異。例如:libedit 已知與 libreadline 的行為不同。

readline.set_completer_delims(string)
readline.get_completer_delims()

設定或獲取補全的單詞分隔符。這些確定了要考慮補全的單詞的開頭(補全範圍)。這些函式訪問底層庫中的 rl_completer_word_break_characters 變數。

readline.set_completion_display_matches_hook([function])

設定或移除補全顯示函式。如果指定了 *function*,它將用作新的補全顯示函式;如果省略或為 None,則移除任何已安裝的補全顯示函式。這會設定或清除底層庫中的 rl_completion_display_matches_hook 回撥。補全顯示函式以 function(substitution, [matches], longest_match_length) 的形式呼叫,每次需要顯示匹配項時呼叫一次。

示例

以下示例演示瞭如何使用 readline 模組的歷史讀取和寫入函式來自動載入和儲存使用者主目錄中名為 .python_history 的歷史檔案。以下程式碼通常會在使用者 PYTHONSTARTUP 檔案中的互動式會話期間自動執行。

import atexit
import os
import readline

histfile = os.path.join(os.path.expanduser("~"), ".python_history")
try:
    readline.read_history_file(histfile)
    # default history len is -1 (infinite), which may grow unruly
    readline.set_history_length(1000)
except FileNotFoundError:
    pass

atexit.register(readline.write_history_file, histfile)

此程式碼實際上在 Python 以 互動模式 執行時自動執行(參見 Readline 配置)。

以下示例實現了相同的目標,但透過僅附加新歷史記錄來支援併發互動式會話。

import atexit
import os
import readline
histfile = os.path.join(os.path.expanduser("~"), ".python_history")

try:
    readline.read_history_file(histfile)
    h_len = readline.get_current_history_length()
except FileNotFoundError:
    open(histfile, 'wb').close()
    h_len = 0

def save(prev_h_len, histfile):
    new_h_len = readline.get_current_history_length()
    readline.set_history_length(1000)
    readline.append_history_file(new_h_len - prev_h_len, histfile)
atexit.register(save, h_len, histfile)

以下示例擴充套件了 code.InteractiveConsole 類以支援歷史記錄儲存/恢復。

import atexit
import code
import os
import readline

class HistoryConsole(code.InteractiveConsole):
    def __init__(self, locals=None, filename="<console>",
                 histfile=os.path.expanduser("~/.console-history")):
        code.InteractiveConsole.__init__(self, locals, filename)
        self.init_history(histfile)

    def init_history(self, histfile):
        readline.parse_and_bind("tab: complete")
        if hasattr(readline, "read_history_file"):
            try:
                readline.read_history_file(histfile)
            except FileNotFoundError:
                pass
            atexit.register(self.save_history, histfile)

    def save_history(self, histfile):
        readline.set_history_length(1000)
        readline.write_history_file(histfile)