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

时间:2017-06-01 10:36:02

标签: python bash

我导入了readline,为我的程序添加了自定义标签。现在我需要保存程序的输出,但任何重定向stdout的尝试都会破坏标签完成功能。

我试过python3 script.py | tee txt.txt女巫似乎最接近打印到stdout和文本文件,但它不起作用。

这里是自定义选项卡完成类,其函数调用来自main(以防万一):

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')

1 个答案:

答案 0 :(得分:0)

这是一个可能的解决方案:“猴子补丁”sys.stdout.write方法,以便写入stdout的任何内容也会被发送到文件。我承认这不是很优雅,但它确实有效。 ;)

我已将Logger类设为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')