파이썬에서 stdout을 "nothing"으로 리디렉션


128

나는 충분히 많은 수의 모듈로 구성된 큰 프로젝트를 가지고 있으며, 각각은 표준 출력으로 무언가를 인쇄합니다. 이제 프로젝트의 규모가 커짐에 따라 더 큰 프로젝트가 없습니다. 의print 상당히 느린 프로그램을 만들었습니다 표준 출력에 많이 인쇄 문.

따라서 런타임 에 stdout에 아무것도 인쇄할지 여부 를 결정하려고합니다 . 모듈이 많기 때문에 모듈을 변경할 수 없습니다. (stdout을 파일로 리디렉션 할 수는 있지만 상당히 느립니다.)

그래서 내 질문은 어떻게 stdout을 아무것도로 리디렉션하지 않는 것입니다. 즉, 어떻게 print진술이 아무것도하지 않게합니까?

# I want to do something like this.
sys.stdout = None         # this obviously will give an error as Nonetype object does not have any write method.

현재 내가 가진 유일한 아이디어는 write 메소드 (아무것도하지 않음)가있는 클래스를 만들고 stdout 을이 클래스의 인스턴스로 리디렉션하는 것입니다.

class DontPrint(object):
    def write(*args): pass

dp = DontPrint()
sys.stdout = dp

파이썬에 내장 메커니즘이 있습니까? 아니면 이것보다 더 좋은 것이 있습니까?



1
방금 특이한 것을 발견했습니다. sys.stdout을 None으로 바꾸는 것은 실제로 내 프로그램에서 작동하지만 이유는 확실하지 않습니다. os.devnull로 리디렉션을 인코딩하는 데 실제로 이상한 문제가 있었으므로 None을 사용해 보았습니다. Django 단위 테스트에서 수행하는 것과 관련이있을 수 있지만 확실하지 않습니다.
Teekin

답변:


233

크로스 플랫폼 :

import os
import sys
f = open(os.devnull, 'w')
sys.stdout = f

Windows에서 :

f = open('nul', 'w')
sys.stdout = f

Linux에서 :

f = open('/dev/null', 'w')
sys.stdout = f

그런 다음 어떻게 취소합니까? 완료 후 인쇄 문을 다시 켜는 방법이 있습니까?
jj172

4
물론 원본에 대한 참조를 저장하고 sys.stdout나중에 다시 설정하십시오. 예를 들어 old_stdout = sys.stdout다른 코드 앞에, sys.stdout = old_stdout완료되면.
Andrew Clark

1
참고 : 파일 디스크립터 수준에서 리디렉션되지 않습니다. 즉, 외부 자식 프로세스의 출력, C stdout으로 직접 인쇄되는 C 확장의 출력을 리디렉션하지 못할 수 있습니다 os.write(1, b'abc\n'). 당신은 필요 os.dup2()참조 파일 기술자 수준에서 리디렉션,stdout_redirected()
JFS를

4
이 참고 sys.__stdout__리디렉션을 취소하십시오. 따라서 sys.stdout = sys.__stdout__백업 만 저장하면됩니다.
Konstantin Sekeresh

28

이 작업을 수행하는 좋은 방법은 인쇄물을 감쌀 작은 컨텍스트 프로세서를 만드는 것입니다. with 하여 모든 출력을 침묵시킵니다.

파이썬 2 :

import os
import sys
from contextlib import contextmanager

@contextmanager
def silence_stdout():
    old_target = sys.stdout
    try:
        with open(os.devnull, "w") as new_target:
            sys.stdout = new_target
            yield new_target
    finally:
        sys.stdout = old_target

with silence_stdout():
    print("will not print")

print("this will print")

파이썬 3.4+ :

Python 3.4에는 이와 같은 컨텍스트 프로세서가 있으므로 간단히 다음과 같이 contextlib를 사용할 수 있습니다.

import contextlib

with contextlib.redirect_stdout(None):
    print("will not print")

print("this will print")

이 코드를 실행하면 첫 번째 출력이 아닌 두 번째 출력 행만 인쇄됩니다.

$ python test.py
this will print

이것은 크로스 플랫폼 (Windows + Linux + Mac OSX)에서 작동하며 다른 답변보다 깨끗합니다.


@celticminstrel 당신이 완전히 옳아 요, 수정 해 주셔서 감사합니다. 나중에 sys.stdout을 재설정하도록 코드를 업데이트했습니다.
Emil Stenström

이것은 일부 오류 검사 누락,하지만 좋은 생각입니다
미친 물리학

파이썬 3에서도 이것이 어떻게 작동하는지 보여주는 코드를 추가했습니다.
Emil Stenström

15

Python 3.4 이상인 경우 표준 라이브러리를 사용하는 간단하고 안전한 솔루션이 있습니다.

import contextlib

with contextlib.redirect_stdout(None):
  print("This won't print!")

3
with contextlib.redirect_stdout(None)뿐만 아니라 작동
크리스 Cogdon에게

@ChrisCogdon 아주 좋은 힌트, 그에 따라 답변을 편집했습니다.
iFreilicht

1
pprint 라이브러리를 사용중인 경우 작동하지 않습니다. AttributeError: 'NoneType' object has no attribute 'write'
Speeeddy

@Speeeddy python 2 에서이 오류가 발생 했습니까? write아무것도하지 않는 더미 메소드 로 클래스를 만들 수 있습니다 . 아래 답변을 참조하십시오.
dizcza

8

(적어도 내 시스템에서는) os.devnull에 쓰는 것이 DontPrint 클래스에 쓰는 것보다 약 5 배 빠릅니다.

#!/usr/bin/python
import os
import sys
import datetime

ITER = 10000000
def printlots(out, it, st="abcdefghijklmnopqrstuvwxyz1234567890"):
   temp = sys.stdout
   sys.stdout = out
   i = 0
   start_t = datetime.datetime.now()
   while i < it:
      print st
      i = i+1
   end_t = datetime.datetime.now()
   sys.stdout = temp
   print out, "\n   took", end_t - start_t, "for", it, "iterations"

class devnull():
   def write(*args):
      pass


printlots(open(os.devnull, 'wb'), ITER)
printlots(devnull(), ITER)

다음과 같은 결과를 얻었습니다.

<open file '/dev/null', mode 'wb' at 0x7f2b747044b0> 
   took 0:00:02.074853 for 10000000 iterations
<__main__.devnull instance at 0x7f2b746bae18> 
   took 0:00:09.933056 for 10000000 iterations

4
다음 번에 시간을
내고 싶을

6

Unix 환경 (Linux 포함)에있는 경우 출력을 /dev/null다음으로 리디렉션 할 수 있습니다 .

python myprogram.py > /dev/null

그리고 Windows의 경우 :

python myprogram.py > nul

2
모든 플랫폼에서 작동하는 솔루션을 사용하는 것이 좋습니다.
Pushpak Dagade

2
@Guanidene, 아마도 자신의 프로그램을 사용하는 유일한 사람이라면 환경을 거의 보장 할 수 있습니다.
Nick Radford

nul = myfunc() ?
Hicsy

2

이건 어때요:

from contextlib import ExitStack, redirect_stdout
import os

with ExitStack() as stack:
    if should_hide_output():
        null_stream = open(os.devnull, "w")
        stack.enter_context(null_stream)
        stack.enter_context(redirect_stdout(null_stream))
    noisy_function()

이것은 contextlib 모듈 의 기능을 사용 하여 결과에 따라 실행하려는 모든 명령의 출력을 숨 깁니다.should_hide_output() 해당 기능이 실행 된 후 출력 동작을 복원합니다.

당신은 표준 오류 출력을 숨기려면 다음 가져올 redirect_stderr에서 contextlib하고 말하는 줄을 추가stack.enter_context(redirect_stderr(null_stream)) .

주요 단점은 이것이 Python 3.4 이상 버전에서만 작동한다는 것입니다.



1

클래스는 잘 작동합니다 ( write()메소드 이름을 제외하고 - write()소문자 로 호출해야 함 ). 그냥 사본을 저장하십시오sys.stdout다른 변수에 .

* NIX를 사용하는 경우 할 수 sys.stdout = open('/dev/null')있지만 자신의 클래스를 롤링하는 것보다 이식성이 떨어집니다.




0
sys.stdout = None

print()경우 도 괜찮습니다 . 그러나 sys.stdout의 메소드를 호출하면 오류가 발생할 수 있습니다 (예 :) sys.stdout.write().

문서 에는 메모 가 있습니다 .

일부 조건에서 stdin, stdout 및 stderr뿐만 아니라 원래 값 stdin , stdoutstderr 는 None 일 수 있습니다. 콘솔에 연결되지 않은 Windows GUI 앱과 pythonw로 시작된 Python 앱의 경우가 일반적입니다.


"확인"과 "인쇄하려고 할 때 오류가 발생하지 않습니다"는이 경우 매우 다릅니다.
미친 물리학 자

1
네가 옳아. 어떤 방법으로도 호출 할 수 없으므로 sys.stdout = Null경우에 따라 위험 할 수 있습니다.
Alexander Chzhen

이 정확한 경우에는 위험한 것으로 알려져 있습니다. OP는 구체적으로 오류를 처리합니다.
미친 물리학 자

0

iFreilicht의 답변 보충 -파이썬 2 및 3 모두에서 작동합니다.

import sys

class NonWritable:
    def write(self, *args, **kwargs):
        pass

class StdoutIgnore:
    def __enter__(self):
        self.stdout_saved = sys.stdout
        sys.stdout = NonWritable()
        return self

    def __exit__(self, *args):
        sys.stdout = self.stdout_saved

with StdoutIgnore():
    print("This won't print!")
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.