일시적으로 stdout / stderr 리디렉션
파이썬에서 stdout / stderr을 일시적으로 리디렉션 할 수 있습니까 (즉, 메서드 기간 동안)?
편집하다:
현재 솔루션의 문제 (처음에는 기억했지만 잊어 버렸음)는 리디렉션 하지 않는다는 것입니다 . 오히려 스트림 전체를 대체합니다. 따라서 메서드 에 어떤 이유로 든 변수 중 하나의 로컬 복사본 이있는 경우 (예 : 스트림이 매개 변수로 무언가에 전달 되었기 때문에) 작동하지 않습니다.
해결책이 있습니까?
일부 함수가 sys.stdout스트림을 로컬 변수로 캐시 하여 전역 sys.stdout을 대체하는 것이 해당 함수 내에서 작동하지 않을 수있는 문제를 해결하려면 파일 설명자 수준 ( sys.stdout.fileno()) 에서 리디렉션 할 수 있습니다 ( 예 :
from __future__ import print_function
import os
import sys
def some_function_with_cached_sys_stdout(stdout=sys.stdout):
print('cached stdout', file=stdout)
with stdout_redirected(to=os.devnull), merged_stderr_stdout():
print('stdout goes to devnull')
some_function_with_cached_sys_stdout()
print('stderr also goes to stdout that goes to devnull', file=sys.stderr)
print('stdout is back')
some_function_with_cached_sys_stdout()
print('stderr is back', file=sys.stderr)
stdout_redirected()모든 출력을 sys.stdout.fileno()지정된 파일 이름, 파일 객체 또는 파일 설명자 ( os.devnull예제)로 리디렉션합니다 .
stdout_redirected()그리고 merged_stderr_stdout()여기에 정의되어 있습니다 .
컨텍스트 관리자에 리디렉션 논리를 넣을 수도 있습니다.
import os
import sys
class RedirectStdStreams(object):
def __init__(self, stdout=None, stderr=None):
self._stdout = stdout or sys.stdout
self._stderr = stderr or sys.stderr
def __enter__(self):
self.old_stdout, self.old_stderr = sys.stdout, sys.stderr
self.old_stdout.flush(); self.old_stderr.flush()
sys.stdout, sys.stderr = self._stdout, self._stderr
def __exit__(self, exc_type, exc_value, traceback):
self._stdout.flush(); self._stderr.flush()
sys.stdout = self.old_stdout
sys.stderr = self.old_stderr
if __name__ == '__main__':
devnull = open(os.devnull, 'w')
print('Fubar')
with RedirectStdStreams(stdout=devnull, stderr=devnull):
print("You'll never see me")
print("I'm back!")
임시 리디렉션이 무엇을 의미하는지 잘 모르겠습니다. 그러나 이와 같이 스트림을 재 할당하고 다시 재설정 할 수 있습니다.
temp = sys.stdout
sys.stdout = sys.stderr
sys.stderr = temp
또한 이와 같은 인쇄 stmts 내에서 sys.stderr에 쓰십시오.
print >> sys.stderr, "Error in atexit._run_exitfuncs:"
일반 인쇄는 표준 출력됩니다.
다음과 같은 데코레이터를 사용하면 가능합니다.
import sys
def redirect_stderr_stdout(stderr=sys.stderr, stdout=sys.stdout):
def wrap(f):
def newf(*args, **kwargs):
old_stderr, old_stdout = sys.stderr, sys.stdout
sys.stderr = stderr
sys.stdout = stdout
try:
return f(*args, **kwargs)
finally:
sys.stderr, sys.stdout = old_stderr, old_stdout
return newf
return wrap
로 사용:
@redirect_stderr_stdout(some_logging_stream, the_console):
def fun(...):
# whatever
또는의 소스를 수정하지 않으려면 다음 fun과 같이 직접 호출하십시오.
redirect_stderr_stdout(some_logging_stream, the_console)(fun)
그러나 이것은 스레드로부터 안전하지 않습니다.
파이썬 3.4부터 컨텍스트 관리자가 있습니다 contextlib.redirect_stdout.
from contextlib import redirect_stdout
with open('yourfile.txt', 'w') as f:
with redirect_stdout(f):
# do stuff...
stdout이 작동 을 완전히 침묵시키기 위해 :
from contextlib import redirect_stdout
with redirect_stdout(None):
# do stuff...
Here's a context manager that I found useful. The nice things about this are that you can use it with the with statement and it also handles redirecting for child processes.
import contextlib
@contextlib.contextmanager
def stdchannel_redirected(stdchannel, dest_filename):
"""
A context manager to temporarily redirect stdout or stderr
e.g.:
with stdchannel_redirected(sys.stderr, os.devnull):
...
"""
try:
oldstdchannel = os.dup(stdchannel.fileno())
dest_file = open(dest_filename, 'w')
os.dup2(dest_file.fileno(), stdchannel.fileno())
yield
finally:
if oldstdchannel is not None:
os.dup2(oldstdchannel, stdchannel.fileno())
if dest_file is not None:
dest_file.close()
The context for why I created this is at this blog post.
Raymond Hettinger shows us a better way[1]:
import sys
with open(filepath + filename, "w") as f: #replace filepath & filename
with f as sys.stdout:
print("print this to file") #will be written to filename & -path
After the with block the sys.stdout will be reset
[1]: http://www.youtube.com/watch?v=OSGv2VnC0go&list=PLQZM27HgcgT-6D0w6arhnGdSHDcSmQ8r3
We'll use the PHP syntax of ob_start and ob_get_contents functions in python3, and redirect the input into a file.
The outputs are being stored in a file, any type of stream could be used as well.
from functools import partial
output_buffer = None
print_orig = print
def ob_start(fname="print.txt"):
global print
global output_buffer
print = partial(print_orig, file=output_buffer)
output_buffer = open(fname, 'w')
def ob_end():
global output_buffer
close(output_buffer)
print = print_orig
def ob_get_contents(fname="print.txt"):
return open(fname, 'r').read()
Usage:
print ("Hi John")
ob_start()
print ("Hi John")
ob_end()
print (ob_get_contents().replace("Hi", "Bye"))
Would print
Hi John Bye John
Look at contextlib.redirect_stdout(new_target) and contextlib.redirect_stderr(new_target). contextlib.redirect_stderr(new_target) is new in Python 3.5.
ReferenceURL : https://stackoverflow.com/questions/6796492/temporarily-redirect-stdout-stderr
'IT TIP' 카테고리의 다른 글
| Xcode, 중복 기호 _main (0) | 2021.01.05 |
|---|---|
| 숫자 범위를 다른 범위에 매핑 (0) | 2021.01.05 |
| 왜 벡터 (0) | 2021.01.05 |
| numpy의 반복되지 않는 난수 (0) | 2021.01.05 |
| Cordova 초기화 오류 : 클래스를 찾을 수 없음 (0) | 2021.01.05 |