2017-04-19 72 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