2011-08-31 5 views
3

경고 메시지를 기록하는 좋은 방법을 찾고 있지만 함수의 호출자 만 알 수있는 정보를 추가하려고합니다.파이썬에서의 thread-safe 경고

예를 들어 명확해질 것이라고 생각합니다.

# log method as parameter 

class Runner1(object): 

    def __init__(self, log): 
     self.log = log 

    def run(self): 
     self.log('First Warning') 
     self.log('Second Warning') 
     return 42 


class Main1(object): 

    def __init__(self): 
     self._runner = Runner1(self.log) 

    def log(self, message): 
     print('Some object specific info: {}'.format(message)) 

    def run(self): 
     print(self._runner.run()) 

e1 = Main1() 
e1.run() 

주 개체에는 모든 메시지에 로깅하기 전에 자체 정보를 추가하는 로그 기능이 있습니다. 이 로그 함수는 매개 변수 (이 경우 Runner 객체)로 제공됩니다. 이 여분의 매개 변수를 항상 가지고 다니는 것은 매우 짜증나 며, 나는 그것을 피하고 싶습니다. 대개는 많은 객체/함수가 있으므로 각 객체마다 다른 로거를 생성해야하므로 로깅 메소드 사용을 폐기했습니다. (이 맞습니까?) 내가 경고 모듈을 사용하여 거품에 경고를 시도

:

# warning module 

import warnings 

class Runner2(object): 

    def run(self): 
     warnings.warn('First Warning') 
     warnings.warn('Second Warning') 
     return 42 


class Main2(object): 

    def __init__(self): 
     self._runner = Runner2() 

    def log(self, message): 
     print('Some object specific info: {}'.format(message)) 

    def run(self): 
     with warnings.catch_warnings(record=True) as ws: 
      warnings.simplefilter("always") 
      out = self._runner.run() 
      for w in ws: 
       self.log(w.message) 
     print(out) 

e2 = Main2() 
e2.run() 

그러나 문서에 따르면,이 스레드로부터 안전하지 않습니다.

# yield warning 

class _Warning(object): 

    def __init__(self, message): 
     self.message = message 


class Runner3(object): 

    def run(self): 
     yield _Warning('First Warning') 
     yield _Warning('Second Warning') 
     yield 42 


class Main3(object): 

    def __init__(self): 
     self._runner = Runner3() 

    def log(self, message): 
     print('Some object specific info: {}'.format(message)) 

    def run(self): 
     for out in self._runner.run(): 
      if not isinstance(out, _Warning): 
       break 
      self.log(out.message) 
     print(out) 


e3 = Main3() 
e3.run() 

하지만 당신은 (대신 반환) 산출하기 Runner.run을 수정해야한다는 사실 최종 결과가 기능해야하므로 불편 :

마지막으로, 나는 또한 일부 발전기를 시도했다 이 방법으로 사용하도록 특별히 변경되었습니다 (어쩌면 이것이 앞으로 변경 될 것입니까? 마지막 QA는 PEP255). 또한이 유형의 구현에 다른 문제가 있는지 확실하지 않습니다.

그래서 내가 찾고있는 것은 매개 변수를 전달할 필요가없는 경고를 버블 링하는 스레드 안전 방식입니다. 또한 경고가없는 메소드는 변경되지 않은 상태로 유지하고 싶습니다. yield 나 warning.warn과 같은 특수 구조를 추가하면 경고를 버블 링 할 수 있습니다.

아이디어가 있으십니까?

답변

2
import Queue 

log = Queue.Queue() 
class Runner1(object): 

    def run(self): 
     log.put('First Warning') 
     log.put('Second Warning') 
     return 42 

class Main1(object): 

    def __init__(self): 
     self._runner = Runner1() 

    def log(self, message): 
     print('Some object specific info: {0}'.format(message)) 

    def run(self): 
     out=self._runner.run() 
     while True: 
      try: 
       msg = log.get_nowait() 
       self.log(msg) 
      except Queue.Empty: 
       break 
     print(out) 


e1 = Main1() 
e1.run() 

는 제안을

Some object specific info: First Warning 
Some object specific info: Second Warning 
42 
+0

감사를 얻을 수 있지만, 아직도 내가 주자로 로거를 제공해야합니다, 나는 비교하여 어떤 이익을 내 예 1이 표시되지 않습니다. – Hernan

+0

@Hernan :'러너 (Runner) '의 모습을 의사 코드로 제공 할 수 있습니까? 로거를 러너에 명시 적으로 전달하지 않고 러너에서 로거를 사용하려면 어떻게해야합니까? 전역 변수를 사용합니까? 폐쇄? 어느 옵션도 나에게 매우 매력적이지는 않습니다 ... – unutbu

+0

사실, 제 2와 3의 예는 제가 찾고있는 것보다 더 적습니다. 러너를 간단하게 유지하고 러너를 호출하는 함수에 약간의 복잡성을 추가하십시오. 예제 2는 스레드로부터 안전하다면 완벽 할 것입니다. 예제 3은 경고가없는 함수가 수정되지 않고 실행된다는 것을 의미하므로 "42를 반환 할 수있다"(yield 42 대신) 완벽한 것입니다. – Hernan