我可以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.encoding
和sys.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中, StringIO
和cStringIO
模块不见了,你应该使用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'