다음과 같은 스크립트가 있다고 가정합니다.
# module writer.py
import sys
def write():
sys.stdout.write("foobar")
이제 write
함수 의 출력을 캡처하고 추가 처리를 위해 변수에 저장 한다고 가정 합니다. 순진한 해결책은 다음과 같습니다.
# module mymodule.py
from writer import write
out = write()
print out.upper()
그러나 이것은 작동하지 않습니다. 다른 해결책을 생각 해냈고 작동하지만 문제를 해결하는 더 좋은 방법이 있는지 알려주세요. 감사
import sys
from cStringIO import StringIO
# setup the environment
backup = sys.stdout
# ####
sys.stdout = StringIO() # capture output
write()
out = sys.stdout.getvalue() # release output
# ####
sys.stdout.close() # close the stream
sys.stdout = backup # restore original stdout
print out.upper() # post processing
답변
설정 stdout
은 합리적인 방법입니다. 다른 하나는 다른 프로세스로 실행하는 것입니다.
import subprocess
proc = subprocess.Popen(["python", "-c", "import writer; writer.write()"], stdout=subprocess.PIPE)
out = proc.communicate()[0]
print out.upper()
답변
다음은 코드의 컨텍스트 관리자 버전입니다. 두 값의 목록을 생성합니다. 첫 번째는 stdout이고 두 번째는 stderr입니다.
import contextlib
@contextlib.contextmanager
def capture():
import sys
from cStringIO import StringIO
oldout,olderr = sys.stdout, sys.stderr
try:
out=[StringIO(), StringIO()]
sys.stdout,sys.stderr = out
yield out
finally:
sys.stdout,sys.stderr = oldout, olderr
out[0] = out[0].getvalue()
out[1] = out[1].getvalue()
with capture() as out:
print 'hi'
답변
향후 방문자를 위해 : Python 3.4 contextlib는 컨텍스트 관리자 를 통해 이를 직접 제공합니다 ( Python contextlib 도움말 참조 ) redirect_stdout
.
from contextlib import redirect_stdout
import io
f = io.StringIO()
with redirect_stdout(f):
help(pow)
s = f.getvalue()
답변
이것은 내 원래 코드의 데코레이터 대응 물입니다.
writer.py
동일하게 유지 :
import sys
def write():
sys.stdout.write("foobar")
mymodule.py
sligthly 수정됩니다 :
from writer import write as _write
from decorators import capture
@capture
def write():
return _write()
out = write()
# out post processing...
그리고 여기에 데코레이터가 있습니다.
def capture(f):
"""
Decorator to capture standard output
"""
def captured(*args, **kwargs):
import sys
from cStringIO import StringIO
# setup the environment
backup = sys.stdout
try:
sys.stdout = StringIO() # capture output
f(*args, **kwargs)
out = sys.stdout.getvalue() # release output
finally:
sys.stdout.close() # close the stream
sys.stdout = backup # restore original stdout
return out # captured output wrapped in a string
return captured
답변
또는 이미 존재하는 기능을 사용할 수도 있습니다.
from IPython.utils.capture import capture_output
with capture_output() as c:
print('some output')
c()
print c.stdout
답변
Python 3부터는 sys.stdout.buffer.write()
(이미) 인코딩 된 바이트 문자열을 stdout에 쓰는 데 사용할 수도 있습니다 ( Python 3의 stdout 참조 ). 당신이 작업을 수행 할 때 간단한 StringIO
어느 쪽도이 때문에 접근이 작동하지 않습니다 sys.stdout.encoding
도 sys.stdout.buffer
사용할 수 없을 것입니다.
Python 2.6부터는 누락 된 속성이 포함 된 TextIOBase
API를 사용할 수 있습니다 .
import sys
from io import TextIOWrapper, BytesIO
# setup the environment
old_stdout = sys.stdout
sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding)
# do some writing (indirectly)
write("blub")
# 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
# do stuff with the output
print(out.upper())
이 솔루션은 Python 2> = 2.6 및 Python 3에서 작동 sys.stdout.write()
합니다. 유니 코드 문자열 sys.stdout.buffer.write()
만 허용하고 바이트 문자열 만 허용합니다. 이것은 이전 코드의 경우가 아닐 수 있지만 변경없이 Python 2 및 3에서 실행되도록 빌드 된 코드의 경우가 많습니다.
stdout.buffer를 사용하지 않고 바이트 문자열을 stdout에 직접 보내는 코드를 지원해야하는 경우 다음 변형을 사용할 수 있습니다.
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에 버퍼의 인코딩을 설정할 필요는 없지만이 방법을 사용하여 스크립트 출력을 테스트 / 비교할 때 도움이됩니다.
답변
여기 의 질문 ( tee
부분이 아닌 출력을 리디렉션하는 방법의 예 )은 os.dup2
OS 수준에서 스트림을 리디렉션하는 데 사용 합니다. 프로그램에서 생성 한 명령에도 적용되기 때문에 좋습니다.