Python模块“readline”无法处理输出重定向

2024-05-01 21:51:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我导入了readline,将定制的制表符补全添加到我的程序中。现在我需要保存程序的输出,但是任何重定向stdout的尝试都会破坏tab completion功能。你知道吗

我试过python3 script.py | tee txt.txt这个开关似乎最接近打印到标准输出和文本文件,但它不起作用。你知道吗

下面是带有main函数调用的自定义tab完成类(以防万一):

import readline

class MyCompleter(object):

    def __init__(self, options):
        self.options = sorted(options)

    def complete(self, text, state):
        if state == 0:  
            if text: 
                self.matches = [s for s in self.options if s and s.startswith(text)]
            else:  
                self.matches = self.options[:]
        try: 
            return self.matches[state]
        except IndexError:
            return None

def readlineset(a): # function called from main to turn on tab completion
                    # a is list of strings
    readline.set_completer(MyCompleter(a).complete)
    readline.parse_and_bind('tab: complete')

Tags: textself程序txtreadlineifmaindef
1条回答
网友
1楼 · 发布于 2024-05-01 21:51:40

这里有一个可能的解决方案:sys.stdout.write方法“monkey patch”,这样写到stdout的任何东西也会被发送到一个文件。我承认这不太优雅,但很管用。;)

我创建了Logger类a Context Manager,这样就可以在with语句中使用它。你知道吗

import readline
import sys

class MyCompleter(object):
    def __init__(self, options):
        self.options = sorted(options)

    def complete(self, text, state):
        if state == 0:
            if text: 
                self.matches = [s for s in self.options if s and s.startswith(text)]
            else:
                self.matches = self.options[:]
        try:
            return self.matches[state]
        except IndexError:
            return None

class Logger(object):
    ''' Monkey-patch sys.stdout
        to copy output to a file
    '''
    def __init__(self, fname):
        self.fh = open(fname, 'w')
        self.oldwrite = sys.stdout.write
        sys.stdout.write = self.write

    def write(self, s):
        self.oldwrite(s)
        self.fh.write(s)

    def close(self):
        self.fh.close()
        sys.stdout.write = self.oldwrite

    # Define Context Manager methods so Logger 
    # can be used in a `with` statement
    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()
        return False

def readlineset(a):
    ''' Turn on tab completion. 
        `a` is list of strings that will be completed
    '''
    readline.set_completer(MyCompleter(a).complete)
    readline.parse_and_bind('tab: complete')

def main():
    readlineset(['python', 'stack', 'overflow', 'exchange'])
    with Logger('mylog.txt'):
        while True:
            s = input('> ')
            if s == 'quit':
                break
            print(repr(s), len(s))

    print('bye')

if __name__ == '__main__':
    main()

演示

> This is a test
'This is a test' 14
> python on stack overflow
'python on stack overflow' 24
> quit
bye

mylog.txt文件

'This is a test' 14
'python on stack overflow' 24

如果不想使用with,可以这样使用Logger

def main():
    readlineset(['python', 'stack', 'overflow', 'exchange'])
    logger = Logger('mylog.txt')
    while True:
        s = input('> ')
        if s == 'quit':
            break
        print(repr(s), len(s))

    logger.close()
    print('bye')

相关问题 更多 >