파이썬 함수 호출에서 stdout 출력을 캡처하는 방법은 무엇입니까?
개체에 어떤 작업을 수행하는 Python 라이브러리를 사용하고 있습니다.
do_something(my_object)
그리고 그것을 바꿉니다.그러는 동안 stdout에 통계를 출력하는데, 저는 이 정보를 파악하고 싶습니다.적절한 해결책은 변화하는 것입니다.do_something()관련 정보를 반환합니다.
out = do_something(my_object)
하지만 개발되기까지는 시간이 걸릴 것입니다.do_something()이 문제에 도달합니다.해결책으로, 저는 무엇이든 구문 분석하는 것에 대해 생각했습니다.do_something()stdout에 씁니다.
코드의 두 지점 사이에서 stdout 출력을 캡처하려면 어떻게 해야 합니까?
start_capturing()
do_something(my_object)
out = end_capturing()
?
다음 컨텍스트 관리자를 사용해 보십시오.
from io import StringIO
import sys
class Capturing(list):
def __enter__(self):
self._stdout = sys.stdout
sys.stdout = self._stringio = StringIO()
return self
def __exit__(self, *args):
self.extend(self._stringio.getvalue().splitlines())
del self._stringio # free up some memory
sys.stdout = self._stdout
용도:
with Capturing() as output:
do_something(my_object)
output이제 함수 호출에 의해 인쇄된 행을 포함하는 목록입니다.
고급 사용:
명확하지 않은 것은 이 작업이 두 번 이상 수행될 수 있으며 결과는 다음과 관련되어 있다는 것입니다.
with Capturing() as output:
print('hello world')
print('displays on screen')
with Capturing(output) as output: # note the constructor argument
print('hello world2')
print('done')
print('output:', output)
출력:
displays on screen
done
output: ['hello world', 'hello world2']
업데이트: 추가되었습니다.redirect_stdout()파이썬 3.4에서 (와 함께)redirect_stderr()그래서 당신은 사용할 수 있습니다.io.StringIO유사한 결과를 달성하기 위해 그것과 함께 (하지만).Capturing상황에 맞는 관리자뿐만 아니라 목록이 되는 것이 거의 틀림없이 더 편리합니다.
python >= 3.4에서 contextlib에는 데코레이터가 포함되어 있습니다.다음과 같이 질문에 대답하는 데 사용할 수 있습니다.
import io
from contextlib import redirect_stdout
f = io.StringIO()
with redirect_stdout(f):
do_something(my_object)
out = f.getvalue()
문서에서:
sys.stdout을 다른 파일 또는 파일과 유사한 개체로 일시적으로 리디렉션하기 위한 컨텍스트 관리자입니다.
이 도구는 출력이 stdout에 유선 연결된 기존 함수 또는 클래스에 유연성을 추가합니다.
예를 들어 help()의 출력은 일반적으로 sys.stdout으로 전송됩니다.출력을 io로 리디렉션하여 해당 출력을 문자열로 캡처할 수 있습니다.StringIO 개체:
f = io.StringIO() with redirect_stdout(f): help(pow) s = f.getvalue()도움말()의 출력을 디스크의 파일로 보내려면 출력을 일반 파일로 리디렉션합니다.
with open('help.txt', 'w') as f: with redirect_stdout(f): help(pow)help()의 출력을 sys.stderr로 전송하는 방법
with redirect_stdout(sys.stderr): help(pow)sys.stdout에 대한 글로벌 부작용은 이 컨텍스트 관리자가 라이브러리 코드 및 대부분의 스레드 응용 프로그램에서 사용하기에 적합하지 않다는 것을 의미합니다.하위 프로세스의 출력에도 영향을 미치지 않습니다.그러나 여전히 많은 유틸리티 스크립트에 유용한 접근 방식입니다.
이 컨텍스트 관리자는 다시 입력할 수 있습니다.
다음은 파일 파이프를 사용하는 비동기 솔루션입니다.
import threading
import sys
import os
class Capturing():
def __init__(self):
self._stdout = None
self._stderr = None
self._r = None
self._w = None
self._thread = None
self._on_readline_cb = None
def _handler(self):
while not self._w.closed:
try:
while True:
line = self._r.readline()
if len(line) == 0: break
if self._on_readline_cb: self._on_readline_cb(line)
except:
break
def print(self, s, end=""):
print(s, file=self._stdout, end=end)
def on_readline(self, callback):
self._on_readline_cb = callback
def start(self):
self._stdout = sys.stdout
self._stderr = sys.stderr
r, w = os.pipe()
r, w = os.fdopen(r, 'r'), os.fdopen(w, 'w', 1)
self._r = r
self._w = w
sys.stdout = self._w
sys.stderr = self._w
self._thread = threading.Thread(target=self._handler)
self._thread.start()
def stop(self):
self._w.close()
if self._thread: self._thread.join()
self._r.close()
sys.stdout = self._stdout
sys.stderr = self._stderr
사용 예:
from Capturing import *
import time
capturing = Capturing()
def on_read(line):
# do something with the line
capturing.print("got line: "+line)
capturing.on_readline(on_read)
capturing.start()
print("hello 1")
time.sleep(1)
print("hello 2")
time.sleep(1)
print("hello 3")
capturing.stop()
또한 @kindall과 @ForeveWintr의 답변을 활용하여 이를 달성하는 클래스가 있습니다.이전 답변과의 주요 차이점은 이것이 그것을 문자열로 캡처한다는 것입니다.StringIO작업하기에 훨씬 편리한 객체!
import io
from collections import UserString
from contextlib import redirect_stdout
class capture(UserString, str, redirect_stdout):
'''
Captures stdout (e.g., from ``print()``) as a variable.
Based on ``contextlib.redirect_stdout``, but saves the user the trouble of
defining and reading from an IO stream. Useful for testing the output of functions
that are supposed to print certain output.
'''
def __init__(self, seq='', *args, **kwargs):
self._io = io.StringIO()
UserString.__init__(self, seq=seq, *args, **kwargs)
redirect_stdout.__init__(self, self._io)
return
def __enter__(self, *args, **kwargs):
redirect_stdout.__enter__(self, *args, **kwargs)
return self
def __exit__(self, *args, **kwargs):
self.data += self._io.getvalue()
redirect_stdout.__exit__(self, *args, **kwargs)
return
def start(self):
self.__enter__()
return self
def stop(self):
self.__exit__(None, None, None)
return
예:
# Using with...as
with capture() as txt1:
print('Assign these lines')
print('to a variable')
# Using start()...stop()
txt2 = capture().start()
print('This works')
print('the same way')
txt2.stop()
print('Saved in txt1:')
print(txt1)
print('Saved in txt2:')
print(txt2)
이는 Sc.capture()로 Sciris에 구현됩니다.
에 기반을 둔kindall그리고.ForeverWintr의 대답.
는 내가만을 .redirect_stdout입니다.Python<3.4:
import io
from contextlib import contextmanager
@contextmanager
def redirect_stdout(f):
try:
_stdout = sys.stdout
sys.stdout = f
yield
finally:
sys.stdout = _stdout
f = io.StringIO()
with redirect_stdout(f):
do_something()
out = f.getvalue()
언급URL : https://stackoverflow.com/questions/16571150/how-to-capture-stdout-output-from-a-python-function-call
'programing' 카테고리의 다른 글
| TSQL에서 증분 날짜의 결과 집합 생성 (0) | 2023.06.21 |
|---|---|
| '#selector'는 Objective-C에 노출되지 않는 방법을 말합니다. (0) | 2023.06.21 |
| 영업일(예: 주말 무시)만 고려하여 날짜에 일 수를 추가하는 방법은 무엇입니까? (0) | 2023.06.21 |
| 사용자 지정 SSH 포트에서 Git (0) | 2023.06.21 |
| GitHub에서 여러 개의 꺼내기 요청을 여는 방법 (0) | 2023.06.21 |