2017-04-19 84 views
2

我正在使用對象代碼的警告提醒用戶有事情發生,但沒有停止代碼。下面是基於更復雜的情況,我在我的實際代碼遇到一個簡單的樣機:Python的警告來後,事情試圖警告用戶約

from warnings import warn 
class myClass(object):   
    def __init__(self, numberArg): 

     if numberArg > 1000: 
      self._tmpTxt = "That's a really big number for this code." + \ 
          "Code may take a while to run..." 
      warn("\n%s %s" %(numberArg, self._tmpTxt)) 
      print("If this were real code:") 
      print("Actions code takes because this is a big number would happen here.") 

     print("If this were real code, it would be doing more stuff here ...") 

mc1 = myClass(1001) 

在我真正的代碼中,當我實例化的執行__init__(self, numberArg)類,警告是在最後輸出後,所有的遵循警告的處理完成。爲什麼會發生?

更重要的,是有辦法,確保預警輸出第一,然後我的代碼運行的休息,並提供它的輸出?

與這裏提供的示例中,所需作用是提醒什麼事情發生用戶在它發生之前,而不是之後,並提供輸出像警告格式的警告。

注:IPython的/ Jupyter使用Python 2.7時遇到在Windows 7環境

+0

'warn'未從命令行延遲。消息傳遞到stderr,也許你的環境延遲觀看。 – tdelaney

+0

我喜歡warn()的行爲方式。它輸出有問題的模塊名稱,代碼行號,然後輸出粉紅色的警告消息格式以提醒用戶出現問題。有沒有辦法解決這個問題?想法歡迎。 (只是想讓我的代碼更好)。注意:關於延遲理論,雖然本例中的代碼是簡單的,但在我的實際代碼中,計算需要3分鐘以上才能完成,並且最後仍會出現警告。如果是延遲,它似乎是「延遲到所有代碼完成」而不是基於時間。 – TMWP

+1

怎麼樣沖洗stderr?無論如何,這會有所幫助嗎? – direprobs

回答

2

@direprobs提供最簡單的答案在評論這個問題,此問題。在致電warn()後添加以下代碼行。

sys.stderr.flush()

注:雖然它來自sys庫,因爲warnings寫入stderr並已導入庫中,你不需要一個import聲明。

該代碼可以被複制和粘貼成Python 2.7(Jupyter筆記本電腦)快速運行一下,看看效果:

實驗一(用於比較的代碼,如下的話):

# Note how warnings in this sample are held until after code is run and then output at the end ... 

from warnings import warn 
from warnings import resetwarnings 

class myClass(object):   
    def __init__(self, numberArg): 

     if numberArg > 1000: 
      self._tmpTxt = "That's a really big number for this code." + \ 
          "Code may take a while to run..." 
      warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1, category=RuntimeWarning) 
                 # possible categories (some of them): 
                 # UserWarning, Warning, RunTimeWarning, ResourceWarning 
                 # stacklevel was a experiment w/ no visible effect 
                 # in this instance 

      resetwarnings()       # tried putting this before and after the warn() 
      print("If this were real code:") 
      print("Actions code takes because this is a big number would happen here.") 

     print("If this were real code, it would be doing more stuff here ...") 

mc1 = myClass(1001) 

實驗二:

# In this case, we want the warning to come before code execution. This is easily fixed as shown below. 
# note: removed some extraneous useless stuff, the line to look for is sys.stderr.flush() 

from warnings import warn 
from warnings import resetwarnings 

class myClass(object):   
    def __init__(self, numberArg): 

     if numberArg > 1000: 
      self._tmpTxt = "That's a really big number for this code." + \ 
          "Code may take a while to run..." 
      warn("\n%s %s" %(numberArg, self._tmpTxt), category=Warning)    
      sys.stderr.flush()       # put this after each warn() to make it output more immediately 
      print("If this were real code:") 
      print("Actions code takes because this is a big number would happen here.") 

     print("If this were real code, it would be doing more stuff here ...") 

mc1 = myClass(1001) 

實驗三:

# code provided as an experiment ... may be updated later with a more useful example ... 
# in theory, filterwarnings should help shake out repeat warnings if used with right arguments 
# * note how our loop causes the content to print twice, and in theory, the 3 instances of warnings 
# * occur twice each for 6 possible output warnings 
# * each new occurance (3 of them) still outputs, but when the same ones come up again, they don't 
# * we get 3 instead of 6 warnings ... this should be the effect of filterwarning("once") 
#  in this instance 

# help on this: https://docs.python.org/3/library/warnings.html#warning-filter 
#    in this example: 
#     "once" arg = print only the first occurrence of matching warnings, regardless of location 

from warnings import warn 
from warnings import resetwarnings 
from warnings import filterwarnings 

class myClass(object):   
    def __init__(self, numberArg): 

     for i in [1,2]: 

      if numberArg > 1000: 
       print("loop count %d:" %(i)) 
       self._tmpTxt = "That's a really big number for this code." + \ 
           "Code may take a while to run..." 
       filterwarnings("once") 
       warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1, category=RuntimeWarning) 
       sys.stderr.flush() # this provides warning ahead of the output instead of after it 
       # resetwarnings() # no noticeable effect on the code 
       print("If this were real code:") 
       print("Actions code takes because this is a big number would happen here.") 

      if numberArg > 20000: 
       self._tmpTxt = "That's a really really really big number for this code." + \ 
           "Code may take a while to run..."     
       filterwarnings("once", "\nFW: %s %s" %(numberArg, self._tmpTxt)) 
       warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=0) 
       # resetwarnings() # no noticeable effect on the code 
       sys.stderr.flush() # this provides warning ahead of the output instead of after it 

      print("loop count %d:" %(i))  
      print("If this were real code, it would be doing more stuff here ...") 

mc1 = myClass(1001) 
print("====================") 
mc2 = myClass(20001) 

查找後該代碼在GitHub上。張貼在這裏幫助其他人調查如何使用warnings