我可以redirect在Python的标准输出到某种types的string缓冲区?

我使用python的ftplib来编写一个小型的FTP客户端,但是一些包中的函数不返回string输出,而是打印到stdout 。 我想redirectstdout到一个对象,我将能够读取输出。

我知道stdout可以redirect到任何常规文件:

 stdout = open("file", "a") 

但我更喜欢一种不使用本地驱动器的方法。

我正在寻找像Java中的BufferedReader ,可以用来将缓冲区包装到stream中。

 from cStringIO import StringIO import sys old_stdout = sys.stdout sys.stdout = mystdout = StringIO() # blah blah lots of code ... sys.stdout = old_stdout # examine mystdout.getvalue() 

只要添加上面的Ned的答案:你可以使用这个来redirect输出到任何实现write(str)方法的对象

这可以用来在GUI应用程序中“捕捉”标准输出。

这是PyQt中的一个愚蠢的例子:

 import sys from PyQt4 import QtGui class OutputWindow(QtGui.QPlainTextEdit): def write(self, txt): self.appendPlainText(str(txt)) app = QtGui.QApplication(sys.argv) out = OutputWindow() sys.stdout=out out.show() print "hello world !" 

Python 3.4中有contextlib.redirect_stdout()函数 :

 import io from contextlib import redirect_stdout with io.StringIO() as buf, redirect_stdout(buf): print('redirected') output = buf.getvalue() 

下面是代码示例,演示如何在较早的Python版本上实现它 。

使用pipe()并写入适当的文件描述符。

https://docs.python.org/library/os.html#file-descriptor-operations

从Python 2.6开始,您可以使用任何实现来自io模块的TextIOBase API作为替代。 此解决scheme还使您能够使用Python 3中的sys.stdout.buffer.write()将已编码的字节string写入stdout(请参阅Python 3中的stdout )。 使用StringIO将无法正常工作,因为sys.stdout.encodingsys.stdout.buffer都不可用。

使用TextIOWrapper的解决scheme:

 import sys from io import TextIOWrapper, BytesIO # setup the environment old_stdout = sys.stdout sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding) # do something that writes to stdout or stdout.buffer # get output sys.stdout.seek(0) # jump to the start out = sys.stdout.read() # read output # restore stdout sys.stdout.close() sys.stdout = old_stdout 

此解决scheme适用于Python 2> = 2.6和Python 3。

请注意,我们的新sys.stdout.write()只接受unicodestring,而sys.stdout.buffer.write()只接受字节string。 这可能不是旧代码的情况,但是对于构build在Python 2和3上运行而不进行更改的代码通常是这种情况,而这又经常使用sys.stdout.buffer

您可以构build一个接受unicode和字节stringwrite()的细微变化:

 class StdoutBuffer(TextIOWrapper): def write(self, string): try: return super(StdoutBuffer, self).write(string) except TypeError: # redirect encoded byte strings directly to buffer return super(StdoutBuffer, self).buffer.write(string) 

您不必设置sys.stdout.encoding的缓冲区编码,但是当使用此方法testing/比较脚本输出时,这有帮助。

即使存在exception,此方法也会恢复sys.stdout。 它也会在exception之前得到任何输出。

 real_stdout = sys.stdout fake_stdout = io.BytesIO() try: sys.stdout = fake_stdout # do what you gotta do to create some output finally: sys.stdout = real_stdout output_string = fake_stdout.getvalue() fake_stdout.close() # do what you want with the output_string 

我只在Python 2.7.10中testing过,但传闻io.BytesIO是Python 3中的StringIO的替代品 。

在Python3.6中, StringIOcStringIO模块不见了,你应该使用io.StringIO代替。所以你应该像第一个回答那样做:

 import sys from io import StringIO old_stdout = sys.stdout old_stderr = sys.stderr my_stdout = sys.stdout = StringIO() my_stderr = sys.stderr = StringIO() # blah blah lots of code ... sys.stdout = self.old_stdout sys.stderr = self.old_stderr // if you want to see the value of redirect output, be sure the std output is turn back print(my_stdout.getvalue()) print(my_stderr.getvalue()) my_stdout.close() my_stderr.close() 

python3的上下文pipe理器:

 import sys from io import StringIO class redirected_stdout: def __init__(self): self._stdout = None self._string_io = None def __enter__(self): self._stdout = sys.stdout sys.stdout = self._string_io = StringIO() return self def __exit__(self, type, value, traceback): sys.stdout = self._stdout @property def string(self): return self._string_io.getvalue() 

像这样使用:

 >>> with redirected_stdout() as out: >>> print('asdf') >>> s = out.string >>> print('bsdf') >>> print(s, out.string) 'asdf\n' 'asdf\nbsdf\n'