programing

stdout을 일종의 문자열 버퍼로 리디렉션할 수 있습니까?

bestprogram 2023. 7. 1. 09:07

stdout을 일종의 문자열 버퍼로 리디렉션할 수 있습니까?

나는 파이썬의 것을 사용하고 있습니다.ftplib 클라이언트를출력을 "" "FTP 클라트를패쓰일기다문작"로 인쇄합니다.stdout리디렉션하려는 경우stdout내가 출력을 읽을 수 있는 객체로.

알고있어요stdout다음을 사용하여 일반 파일로 리디렉션할 수 있습니다.

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

하지만 저는 로컬 드라이브를 사용하지 않는 방법을 선호합니다.

저는 그와 같은 것을 찾고 있습니다.BufferedReaderJava에서 버퍼를 스트림으로 래핑하는 데 사용할 수 있습니다.

from cStringIO import StringIO # Python3 use: from io import StringIO
import sys

old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()

# blah blah lots of code ...

sys.stdout = old_stdout

# examine mystdout.getvalue()

Python 3.4+에는 다음과 같은 기능이 있습니다.

import io
from contextlib import redirect_stdout

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

다음은 이전 Python 버전에서 구현하는 방법을 보여주는 코드 예제입니다.

위의 Ned의 답변에 추가하자면, 이를 사용하여 쓰기(str) 메서드를 구현하는 모든 개체로 출력을 리디렉션할 수 있습니다.

이는 GUI 응용 프로그램에서 stdout 출력을 "캐치"하는 데 효과적으로 사용할 수 있습니다.

다음은 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 !"

python3의 컨텍스트 관리자:

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'

Python 2.6부터는 API를 구현하는 모든 것을 대체하여 사용할 수 있습니다.또한 이 솔루션을 사용하면sys.stdout.buffer.write()(이미) 인코딩된 바이트 문자열을 표준 출력에 쓸 수 있습니다(Python 3의 stdout 참조).사용.io.StringIO안 것 같아요. 둘 다 안 되니까요, 왜하면둘다, 냐러다이.sys.stdout.buffer도 아니다sys.stdout.encoding가능할 것 같습니다.

다을사용솔루를 io.TextIOWrapper:

import io
import sys

# Setup stdout.
old_stdout = sys.stdout
sys.stdout = io.TextIOWrapper(io.BytesIO(), sys.stdout.encoding)

# Write to stdout or stdout.buffer.
...

# Read from stdout.
sys.stdout.seek(0)
out = sys.stdout.read()

# Restore stdout.
sys.stdout.close()
sys.stdout = old_stdout

이 솔루션은 Python 2 >= 2.6 및 Python 3에서 작동합니다.

참고로 새 제품은sys.stdout.write()유니코드 문자열만 허용하고sys.stdout.buffer.write()바이트 문자열만 허용합니다.할 수 변경 Python 2 및에 3 실록도구코를 합니다.sys.stdout.buffer.

그래서 가지려고sys.stdout.write() 문자열과 문자열을 할 수 . 이 유코드문문바모을수있다습니사를 사용할 수 .io.TextIOWrapper하위 클래스:

class StdoutBuffer(io.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그러나 스크립트 출력을 테스트/테스트하는 데 이 방법을 사용하는 경우에는 도움이 됩니다.

이 메서드는 예외가 있더라도 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

다음을 사용하여 Python 2.7.10에서 테스트됨

다음을 사용하여 Python 3.6.4에서 테스트됨


Bob, 수정/확장 코드 실험으로 인해 어떤 의미로든 흥미로워질 수 있다고 생각되는 경우 추가됨, 그렇지 않으면 삭제하십시오.

비망록에 대한 몇 ... 실행 가능한 역학을 찾는 동안의 확장된 실험에서 출력물을 "잡는" 것에 대한 몇 가지 의견이 있습니다.numexpr.print_versions()에 직접<stdout>(GUI 청소 및 디버깅 보고서로 세부 정보 수집이 필요한 경우)

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

Python 3.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()

사용하다pipe()적절한 파일 설명자에게 씁니다.

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

여기 이것에 대한 또 다른 견해가 있습니다. contextlib.redirect_stdout와 함께io.StringIO()문서화된 것처럼 훌륭하지만, 여전히 일상적으로 사용하기에는 약간 장황합니다.하위 분류를 통해 원라이너로 만드는 방법은 다음과 같습니다.contextlib.redirect_stdout:

import sys
import io
from contextlib import redirect_stdout

class capture(redirect_stdout):

    def __init__(self):
        self.f = io.StringIO()
        self._new_target = self.f
        self._old_targets = []  # verbatim from parent class

    def __enter__(self):
        self._old_targets.append(getattr(sys, self._stream))  # verbatim from parent class
        setattr(sys, self._stream, self._new_target)  # verbatim from parent class
        return self  # instead of self._new_target in the parent class

    def __repr__(self):
        return self.f.getvalue()  

__enter__이(가) 자동으로 반환되므로 차단이 종료된 후 컨텍스트 관리자 개체를 사용할 수 있습니다.또한 __repr__ 메서드 덕분에 컨텍스트 관리자 개체의 문자열 표현은 실제로 stdout입니다.그래서 이제 당신은,

with capture() as message:
    print('Hello World!')
print(str(message)=='Hello World!\n')  # returns True

언급URL : https://stackoverflow.com/questions/1218933/can-i-redirect-the-stdout-into-some-sort-of-string-buffer