Python 我可以将stdout重定向到某种字符串缓冲区吗?

Python 我可以将stdout重定向到某种字符串缓冲区吗?,python,stream,stdout,redirect,Python,Stream,Stdout,Redirect,我正在使用python的ftplib编写一个小型FTP客户端,但是包中的一些函数不返回字符串输出,而是打印到stdout。我想将stdout重定向到一个可以从中读取输出的对象 我知道stdout可以重定向到任何常规文件,其中包括: stdout = open("file", "a") 但我更喜欢不使用本地驱动器的方法 我正在寻找类似Java中的BufferedReader的东西,可以用来将缓冲区包装到流中。使用pipe()并写入适当的文件描述符 只需补充Ned的上述答案:您可以使用此选项将输出

我正在使用python的
ftplib
编写一个小型FTP客户端,但是包中的一些函数不返回字符串输出,而是打印到
stdout
。我想将
stdout
重定向到一个可以从中读取输出的对象

我知道
stdout
可以重定向到任何常规文件,其中包括:

stdout = open("file", "a")
但我更喜欢不使用本地驱动器的方法

我正在寻找类似Java中的
BufferedReader
的东西,可以用来将缓冲区包装到流中。

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


只需补充Ned的上述答案:您可以使用此选项将输出重定向到实现写入(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 !"

从Python2.6开始,您可以使用io模块中实现的任何东西作为替代。 此解决方案还允许您使用Python 3中的
sys.stdout.buffer.write()
将(已经)编码的字节字符串写入stdout(请参阅)。 使用
StringIO
将不起作用,因为
sys.stdout.encoding
sys.stdout.buffer
都不可用

使用TextIOWrapper的解决方案:

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
此解决方案适用于Python2>=2.6和Python3

请注意,我们新的
sys.stdout.write()
只接受unicode字符串,而
sys.stdout.buffer.write()
只接受字节字符串。 对于旧代码来说可能不是这样,但是对于构建为在Python 2和3上运行而不做任何更改的代码来说通常是这样的,这同样经常使用
sys.stdout.buffer

您可以为
write()

您不必将缓冲区的编码设置为sys.stdout.encoding,但这有助于使用此方法测试/比较脚本输出。

在Python 3.4+中有一个:

import io
from contextlib import redirect_stdout

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

下面是一个。

即使出现异常,此方法也会恢复sys.stdout。它还获取异常之前的任何输出

import io
import sys

real_stdout = sys.stdout
fake_stdout = io.BytesIO()   # or perhaps io.StringIO()
try:
    sys.stdout = fake_stdout
    # do what you have to 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
在Python2.7.10中使用

在Python 3.6.4中使用


Bob,添加了一个案例,如果您觉得修改/扩展代码实验中的任何内容在任何意义上都可能变得有趣,否则请随意删除它

广告信息。。。在找到一些可行的机制来“获取”输出时,扩展实验中的几句话由
numexpr.print_versions()
直接指向
(需要清理GUI并将详细信息收集到调试报告中时)

#这简直是天方夜谭:正如鲍勃·斯坦(Bob Stein)多年前提出的:
#py2令人惊讶:
#
输入io
导入系统
#
real_stdout=sys.stdout#推送(存储到real)
fake_stdout=io.BytesIO()#.DEF fake_
尝试:#融合。尝试:
sys.stdout.flush()#.flush()之前
sys.stdout=false#u stdout#。设置为使用false_
#--------------------------------------------做你必须做的事情来创建一些输出
打印123456789#+
导入numexpr#+
QuantFX.numexpr.\uuuuu version\uuuuuuu#+[3]通过伪标准重新分配,正如bufferred+“late”延迟一样。get_value()-读入打印,最终到达->真标准
QuantFX.numexpr.print_versions()#+[4]通过伪标准输出重新分配,正如bufferred+“延迟”延迟一样。get_value()-读入打印,最终到达->真实标准输出
_=os.system('echo os.system()redir')#+[1]通过real_stdout+“late”延迟。get_value()-读入打印,以最终到达->real_stdout,如果没有(#=)-从RET-d“bytesWrite”中捕获/避免在假stdout中被注入
_=os.write(sys.stderr.fileno(),#+[2]通过stderr+“late”延迟。获取_值()-读入打印,最终到达->真实的_标准输出,如果不是(=)-从RET-d“byteswrite”捕获)/避免被注入假标准输出
b'os.write()redir ed')#*否则,如果通过伪标准,则执行回溯(最后一次调用):
# ----------------------------------------- #           ?                              io.UnsupportedOperation:文件号
#'''                                                    ? 但是:列出了一个.fileno()方法
#>>>目录中的“fileno”(sys.stdout)->True?有没有广告,,
#>>>通过;sys.stdout.fileno->
#>>>通过;sys.stdout.fileno()->回溯(最近的上次调用):
#文件“”,第1行,在
#io.UnsupportedOperation:文件号
#                                                       ? 但是拒绝使用它
#'''
最后:#==最后:
sys.stdout.flush()#.flush()在返回实际值之前_
sys.stdout=real_stdout#。设置为使用POP'd real_
返回后的sys.stdout.flush()#.flush()_
out_string=false_stdout.getvalue()#。从false获取字符串_
假的stdout.close()#.close()
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#用out#字符串做你想做的事
#
打印“\n{0:}\n{1:}{0:}”.format(60*“/\”,#“LATE”延迟打印到达最末端的输出字符串->real\u stdo
import io
from contextlib import redirect_stdout

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

real_stdout = sys.stdout
fake_stdout = io.BytesIO()   # or perhaps io.StringIO()
try:
    sys.stdout = fake_stdout
    # do what you have to 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
# THIS WORKS AS HELL: as Bob Stein proposed years ago:
#  py2 SURPRISEDaBIT:
#
import io
import sys
#
real_stdout = sys.stdout                        #           PUSH <stdout> ( store to REAL_ )
fake_stdout = io.BytesIO()                      #           .DEF FAKE_
try:                                            # FUSED .TRY:
    sys.stdout.flush()                          #           .flush() before
    sys.stdout = fake_stdout                    #           .SET <stdout> to use FAKE_
    # ----------------------------------------- #           +    do what you gotta do to create some output
    print 123456789                             #           + 
    import  numexpr                             #           + 
    QuantFX.numexpr.__version__                 #           + [3] via fake_stdout re-assignment, as was bufferred + "late" deferred .get_value()-read into print, to finally reach -> real_stdout
    QuantFX.numexpr.print_versions()            #           + [4] via fake_stdout re-assignment, as was bufferred + "late" deferred .get_value()-read into print, to finally reach -> real_stdout
    _ = os.system( 'echo os.system() redir-ed' )#           + [1] via real_stdout                                 + "late" deferred .get_value()-read into print, to finally reach -> real_stdout, if not ( _ = )-caught from RET-d "byteswritten" / avoided from being injected int fake_stdout
    _ = os.write(  sys.stderr.fileno(),         #           + [2] via      stderr                                 + "late" deferred .get_value()-read into print, to finally reach -> real_stdout, if not ( _ = )-caught from RET-d "byteswritten" / avoided from being injected int fake_stdout
                       b'os.write()  redir-ed' )#  *OTHERWISE, if via fake_stdout, EXC <_io.BytesIO object at 0x02C0BB10> Traceback (most recent call last):
    # ----------------------------------------- #           ?                              io.UnsupportedOperation: fileno
    #'''                                                    ? YET:        <_io.BytesIO object at 0x02C0BB10> has a .fileno() method listed
    #>>> 'fileno' in dir( sys.stdout )       -> True        ? HAS IT ADVERTISED,
    #>>> pass;            sys.stdout.fileno  -> <built-in method fileno of _io.BytesIO object at 0x02C0BB10>
    #>>> pass;            sys.stdout.fileno()-> Traceback (most recent call last):
    #                                             File "<stdin>", line 1, in <module>
    #                                           io.UnsupportedOperation: fileno
    #                                                       ? BUT REFUSES TO USE IT
    #'''
finally:                                        # == FINALLY:
    sys.stdout.flush()                          #           .flush() before ret'd back REAL_
    sys.stdout = real_stdout                    #           .SET <stdout> to use POP'd REAL_
    sys.stdout.flush()                          #           .flush() after  ret'd back REAL_
    out_string = fake_stdout.getvalue()         #           .GET string           from FAKE_
    fake_stdout.close()                         #                <FD>.close()
    # +++++++++++++++++++++++++++++++++++++     # do what you want with the out_string
    #
    print "\n{0:}\n{1:}{0:}".format( 60 * "/\\",# "LATE" deferred print the out_string at the very end reached -> real_stdout
                                     out_string #                   
                                     )
'''
PASS'd:::::
...
os.system() redir-ed
os.write()  redir-ed
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
123456789
'2.5'
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Numexpr version:   2.5
NumPy version:     1.10.4
Python version:    2.7.13 |Anaconda 4.0.0 (32-bit)| (default, May 11 2017, 14:07:41) [MSC v.1500 32 bit (Intel)]
AMD/Intel CPU?     True
VML available?     True
VML/MKL version:   Intel(R) Math Kernel Library Version 11.3.1 Product Build 20151021 for 32-bit applications
Number of threads used by default: 4 (out of 4 detected cores)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
>>>

EXC'd :::::
...
os.system() redir-ed
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
123456789
'2.5'
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Numexpr version:   2.5
NumPy version:     1.10.4
Python version:    2.7.13 |Anaconda 4.0.0 (32-bit)| (default, May 11 2017, 14:07:41) [MSC v.1500 32 bit (Intel)]
AMD/Intel CPU?     True
VML available?     True
VML/MKL version:   Intel(R) Math Kernel Library Version 11.3.1 Product Build 20151021 for 32-bit applications
Number of threads used by default: 4 (out of 4 detected cores)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

Traceback (most recent call last):
  File "<stdin>", line 9, in <module>
io.UnsupportedOperation: fileno
'''
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()
import sys
from io import StringIO


class RedirectedStdout:
    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

    def __str__(self):
        return self._string_io.getvalue()
>>> with RedirectedStdout() as out:
>>>     print('asdf')
>>>     s = str(out)
>>>     print('bsdf')
>>> print(s, out)
'asdf\n' 'asdf\nbsdf\n'