2012-08-31 2 views
2

때로는 디버그 출력을 인쇄하는 기능이 주위에 흩어져 있습니다.디버그 인쇄 끄기

def f(debug=False): 
    print = __builtins__.print if debug else lambda *p: None 

을 아니면 내가 디버그 메시지에서 떨어져 뭔가를 인쇄해야하는 경우, 내가 디버그 메시지에 대한 dprint 함수를 만들 : 이와 내가 와서이 디버그 출력을 전환합니다.

debug=False 일 때이 print 문은 코드가 상당히 느려지므로 lambda *p: None이 여전히 호출되며 함수 호출이 느린 것으로 알려져 있습니다.

그래서, 내 질문은 : 그 코드의 성능에 영향을 미치지 않도록 효율적으로 모든 디버그 인쇄를 비활성화 할 수있는 더 좋은 방법이 있나요?


모든 답변은 내 logging 모듈을 사용하지 않는 것에 관한 것입니다. 이 통지에 좋은이지만,이 상당히 코드를 느리게 함수 호출 방지하는 방법을 질문 대답하지 않는다 - 통해 멀리 기능 코드 객체 땜질하여 가능하다면 (예를 들어, (내 경우에는 25 번 모든 줄은 print 진술 또는 다른 방법으로)). 이 답변에서 제시하는 것보다 printlogging.debug으로 바꾸는 것이 더 느려야합니다. 그리고이 질문은 그러한 함수 호출을 완전히 없애는 것에 관한 것입니다.

lambda *p: None 대신 logging을 사용해 보았는데 놀랄 일도 아니고 코드도 더 느려졌습니다. 이러한 인쇄는 25 침체 원인이 어디에


아마 누군가가 코드를보고 싶다 : http://ideone.com/n5PGu

을 그리고 logging 모듈에 대한 아무것도하지 않습니다. 항상 hacks 없이는 강력한 솔루션을 고수하는 것이 좋습니다. 그러나 내가 해킹을 20 줄짜리 일회성 코드 스 니펫에 사용하면 범죄는 없다고 생각합니다.


제한 등

하지,하지만 제안으로, 어쩌면 기능 소스 코드의 일부 라인 (예를 들어 print로 시작)을 삭제하고 다시 컴파일 할 수있어? 나는 아래의 답에이 접근법을 제시했다. 이 솔루션에 대한 의견을 듣고 싶지만이 문제를 해결하는 다른 방법을 환영합니다.

+0

비록 내가 당신의 함수를 사용하지 않는다고하더라도 :'lambda'를 사용하면, 호출 될 때마다 새로운 함수 객체가있게 될 것입니다. 따라서 빈 함수를 대신 사용하면 코드 속도가 느려지지 않을 것입니다. – devsnd

+0

@twall 한 번만 호출됩니다. – ovgolovin

답변

1

네드 BATCHELDERthe comment에 쓴 :

나는 감속이 인수의 계산에 있다고 생각한다. 디버그 기능을 으로 변경하십시오. 이러한 계산을 피하는 방법을 찾고 있어야합니다. 전처리 Python은 혼란 스러울뿐입니다.

그리고 실제로 결과 문자열이 기록되는지 여부에 관계없이 format 메서드로 문자열을 포맷하면 속도 저하가 발생합니다.

따라서 로깅이 발생하지 않으면 문자열 서식을 연기하고 해제해야합니다. 항상 관계없이 경우의 형식 '것 print 달리 메시지가 기록하지 않을 경우

log.debug('formatted message: %s', interpolated_value) 

,이 포맷되지 않습니다 : 이것은 dprint 기능을 리팩토링 또는 다음과 같은 방법으로 log.debug를 사용함으로써 달성 될 수있다 로그되거나 버려 질 것입니다.

log.debug의 연기 된 서식에 대한 해결책은 Martijn Pietershere입니다.

0

해킹으로, 맞습니다. (그리고 지옥에 아무런 기회도 없으므로 그 람다 노프가 앱의 병목 현상입니다.)

그러나 실제로는 logging 모듈을 사용하여 제대로 로깅을 수행해야합니다.

어떻게 수행해야하는지에 대한 기본 예제는 http://docs.python.org/howto/logging.html#logging-basic-tutorial을 참조하십시오.

+0

그'print's가 내 코드를 25 번 느려졌습니다! (이 함수는 숫자 계산 알고리즘이므로 이러한 일이 발생할 수 있습니다). – ovgolovin

+0

'logging' 모듈을 제안 해 주셔서 감사합니다. 하지만 나는 코드 스 니펫에서 20 줄을 길게 사용하는 것이 로깅을 사용하는 것이 과잉이라고 생각한다. – ovgolovin

+0

솔직히 말해서, 나는 25 회 감속에 만족합니다! 그러나 저는이 질문을 호기심에서 벗어났습니다. 어쩌면 내가 그 모든'print' 호출을 어떻게 비활성화시킬 수 있는지 기술이있을 수 있습니다. – ovgolovin

4

대신 logging 모듈을 사용해야합니다. http://docs.python.org/library/logging.html

그런 다음 당신은 당신의 필요에 따라 로그 레벨을 설정할 수 있습니다 참조 및 다른 주제에 대한 로그 여러 로거 객체를 생성합니다.귀하의 경우에는

import logging 
#set your log level 
logging.basicConfig(level=logging.DEBUG) 
logging.debug('This is a log message') 

: 로깅 수준을 설정하면

import logging 
print = __builtins__.print if debug else logging.debug 

이제 기능은 아무것도 인쇄됩니다 : 당신은 단순히 예를 들어, 로그 문 인쇄 문을 대체 할 수 디버그

logging.basicConfig(level=logging.DEBUG) 

그러나 플러스, 당신은 상단에 다른 모든 로깅 기능을 사용할 수 있습니다! logging.error('error!')

+0

'logging.debug'는'lambda * b : None'보다 빠르지 않을까? – ovgolovin

+2

아마도 그렇지 않습니다. 그러나 그것은 당신의 코드를 더 maintainable하게 만들 것입니다. – devsnd

+0

'.debug()'(및 관련 메소드)는 지연 문자열 형식을 지원합니다. '.debug (msg, * args, ** kw)'는 실제로 메시지가 기록 될 경우 전달 된 내용에 따라'msg % args' 또는'msg % kw'로 변환됩니다. –

0

확실히 파이썬의 logging 모듈을 사용해야합니다. 매우 실용적이며 응용 프로그램의 로그 수준을 변경할 수 있습니다. 예 :

>>> import logging 
>>> logging.basicConfig(level=logging.DEBUG) 
>>> logging.debug('Test.') 
DEBUG:root:Test. 
0

또 다른 해결책은 동적으로 모든 drpint 전화를 f의 코드를 편집하고 삭제할 수 있습니다. 그러나이 솔루션은 매우 unrecommended to be used입니다 :

당신이 올바른지,이에 의존해서는 안됩니다, 그것은 잘못 갈 수 있도록 많은 방법이 있습니다. 첫째, Python은 소스 레벨 변환을 위해 설계된 언어가 아니며, 유효 코드를 불필요하게 삭제하지 않고도 comment_1과 같은 변환기 으로 작성하기가 어렵습니다. 둘째, 이 해킹은 모든 종류의 상황에서 깨질 것입니다. 예를 들어, 중첩 된 함수를 정의 할 때 Cython에서 사용되는 경우 어떤 이유로 든 inspect.getsource가 실패 할 때. 파이썬은 동적이기 때문에 실제로 이런 종류의 해킹이 필요하지 않습니다. 동작을 사용자 정의하십시오. 여기

은에 익숙해 싶은 분들을 위해이 방법의 코드입니다 :

from __future__ import print_function 

DEBUG = False 

def dprint(*args,**kwargs): 
    '''Debug print''' 
    print(*args,**kwargs) 

_blocked = False 
def nodebug(name='dprint'): 
    '''Decorator to remove all functions with name 'name' being a separate expressions''' 
    def helper(f):  
     global _blocked 
     if _blocked: 
      return f 

     import inspect, ast, sys 

     source = inspect.getsource(f)   
     a = ast.parse(source) #get ast tree of f 

     class Transformer(ast.NodeTransformer): 
      '''Will delete all expressions containing 'name' functions at the top level''' 
      def visit_Expr(self, node): #visit all expressions 
       try: 
        if node.value.func.id == name: #if expression consists of function with name a 
         return None #delete it 
       except(ValueError): 
        pass 
       return node #return node unchanged 
     transformer = Transformer() 
     a_new = transformer.visit(a) 
     f_new_compiled = compile(a_new,'<string>','exec') 

     env = sys.modules[f.__module__].__dict__ 
     _blocked = True 
     try: 
      exec(f_new_compiled,env) 
     finally: 
      _blocked = False 
     return env[f.__name__]   
    return helper 


@nodebug('dprint')   
def f(): 
    dprint('f() started') 
    print('Important output') 
    dprint('f() ended') 
    print('Important output2') 


f() 

더 많은 정보 : Replacing parts of the function code on-the-fly