2014-04-24 2 views
0

편집 할 수없는 기능이있어서 콘솔에 결과를 인쇄합니다. 그 함수를 호출하는 것이 가능하지만 함수의 내부 코드를 변경하지 않고 콘솔 출력을 파일로 파이프합니까?특정 기능의 파이프 콘솔 출력 - 파이썬

예를 들어, 내가 가진 : 나는 somefunc()을 편집 할 수 있기 때문에 내가 logger를 사용할 수없는

def somefunc(x): 
    print "Hello World", x**x 

def pipeout(func, outfilename) 
    with open('outfilename', 'w') as fout: 
    # somehow pipes out the output... 

.

나는 @A श 위니 च haudhary의 솔루션을 시도하지만 난이 파일은 첫 번째 OUTPUTFILE 이외의 비어 있었다 수없고 또한 다시하고 다시 :

def redirect_output(file_name): 
    def decorator(func): 
    def wrapper(*args): 
     with open(file_name, 'w') as f: 
     original_stdout = sys.stdout 
     sys.stdout = f 
     func(*args) 
     sys.stdout = original_stdout 
    return wrapper 
    return decorator 

def somefunc(x): 
    print x*x 

xs = [1,2,3,4] 

for i in xs: 
    outputfilename = 'results/'+str(i) 
    somefunc = redirect_output(outputfilename)(somefunc) 
    somefunc(i) 
+0

왜이 기능을 편집 할 수 없습니다. 이것은 파이썬이며 모든 기능은 일반 텍스트 파일에 있습니다. – Daniel

+1

라이브러리 함수 일 수 있으므로 배포 될 프로젝트에서 사용해야합니다. 물론 편집 할 수 있지만 때로는하지 말아야합니다. –

+0

그래, 논리적으로 나는 함수를 편집 할 수 있지만 나와 다른 개발자들 사이에 모든 종류의 복잡성을 야기 할 것이고, 병합 충돌을 피하고 스크럼 미팅과 싸우는 것이 가장 좋다.) – alvas

답변

1

sys.stdout은 함수가 호출 될 때 데코레이터를 사용하여 파일 객체로 리디렉션 한 다음 나중에 원래의 STDOUT으로 복원합니다.

import sys 

def redirect_output(file_name): 

    def decorator(func): 
     def wrapper(*args): 
      with open(file_name, 'w') as f: 
       original_stdout = sys.stdout 
       sys.stdout = f 
       func(*args) 
      sys.stdout = original_stdout 
     return wrapper 
    return decorator 

@redirect_output('file.txt') 
def somefunc(x): 
    print "Hello World", x**x 


somefunc(2) 

print 'Hello to console.' 

출력 :

>>> %run so.py 
Hello to console. 
>>> !cat file.txt 
Hello World 4 

업데이트 : 최신 코드의

작업 버전 :

for i in xs: 
    outputfilename = 'results/'+str(i) 
    new_func = redirect_output(outputfilename)(somefunc) 
    #or call it directly 
    #redirect_output(outputfilename)(somefunc)(i) 
    new_func(i) 
+0

그러나 데코레이터는 OP가'somefunc'을 수정할 수 없으므로 추가 레벨의 간접 지정이 필요합니다. 또한 장식 할 수 없다고 가정하기 때문에 데코 레이팅 된 래퍼를 작성해야합니다. 그리고이 경우 전체 데코레이터를 삭제하고 간단한 래퍼를 수행 할 수도 있습니다. –

+1

@JacobodeVera 글쎄, 그들이 모듈에서 함수를 가져오고 있다면, 다른 데코레이터 표기법을 사용할 수 있습니다 :'somefunc = redirect_output ('file.txt') (somefunc)'. –

+0

@Au wini sad haudhary, 나는 여전히 꾸미기 해결책에 문제가 있습니다. 업데이트 된 질문을보십시오. – alvas

1

예, 사용자가 설정할 수있는 해당 파일을 덮어 씁니다 쓰기 액세스 권한이있는 다른 열린 파일에 대한 sys.stdout의 값 그런 다음 sys.__stdout__

으로 다시 설정할 수 있습니다 나는이 전에 잠시이 필요했고 made a context manager :

import sys                               
from StringIO import StringIO 

class OutStreamCapture(object): 
    """ 
    A context manager to replace stdout and stderr with StringIO objects and 
    cache all output. 
    """ 

    def __init__(self): 
     self._stdout = None 
     self._stderr = None 
     self.stdout = None 
     self.stderr = None 

    def __enter__(self): 
     self._stdout = sys.stdout 
     self._stderr = sys.stderr 
     sys.stdout = StringIO() 
     sys.stderr = StringIO() 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     """ 
     Restore original values of stderr and stdout. 
     The captured contents are stored as strings in the stdout and stderr 
     members. 
     """ 
     self.stdout = sys.stdout.getvalue() 
     self.stderr = sys.stderr.getvalue() 
     sys.stdout = self._stdout 
     sys.stderr = self._stderr 

당신은 다음과 같이 사용할 수 있습니다 :

with OutStreamCapture() as osc: 
    somefunc(x) 

을 그리고 당신은 osc.stderrosc.stdout이며, 함수는 stdout과 stderr에 각각 두 개의 문자열을 가지고 있습니다.

임의의 파일을 대신 사용하도록 수정할 수 있습니다.

하십시오 참고 여기에 내가 컨텍스트 관리자에 sys.stdout의 현재 값을 캐시보다는 복원 sys.__stdout__을 사용하고. 이것은 우리가이 컨텍스트를 입력 할 때 stdout이 이미 리다이렉션되었을 수 있기 때문이며, 우리는 원래의 상태로 되돌리고 싶습니다.

+0

OutStreamCapture 클래스에서'AttributeError : __exit__'을 얻었습니다. – alvas

+0

입니다. 왜냐하면 py2.x에는 기본적으로'__exit__'가 없기 때문입니까? – alvas

+0

@alvas 죄송합니다. OutStreamCapture()가 osc :'인 누락 괄호입니다. 다시 시도하십시오. –