2011-08-31 114 views
3

我正試圖找到一種很好的方式來記錄警告消息,但追加了只有函數調用方纔知道的信息。Python中的線程安全警告

我認爲這將是一個例子。

# 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() 

Main對象具有日誌功能,它在記錄日誌之前添加任何消息自己的信息。這個日誌函數是作爲一個參數給出的(在本例中是給一個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'的樣子嗎?您如何期望在Runner中使用記錄器而不將記錄器明確傳遞給Runner?通過使用全局變量?關閉?這兩個選項似乎都不太吸引我... – unutbu

+0

其實,我的例子2和3更多的是我所尋找的。保持跑步者簡單,併爲調用跑步者的功能添加一些複雜性。如果它是線程安全的,則示例2將是完美的。如果我可以「返回42」(而不是yield 42),則示例3將是完美的,因爲這意味着沒有警告的函數將不加修改地運行。 – Hernan