2017-04-19 1 views
2

J'utilise des avertissements dans le code objet pour avertir les utilisateurs que quelque chose s'est passé mais pas pour arrêter le code. Ci-dessous est un simple mockup sur la base des scénarios plus complexes je rencontre dans mon code réel:Des avertissements Python surviennent après que j'essaie d'avertir l'utilisateur

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) 

Dans mon code réel, quand j'instancier la classe qui exécute __init__(self, numberArg), l'avertissement est émis à la fin après tout le traitement qui suit l'avertissement est terminé. Pourquoi cela arrive-t-il? Plus important encore, existe-t-il un moyen de s'assurer que l'avertissement est sorti en premier et que le reste de mon code s'exécute et délivre sa sortie?

Comme avec l'exemple fourni ici, l'effet désiré est d'alerter l'utilisateur de ce qui va se passer avant que cela ne se produise, et non après, et de délivrer la sortie comme un avertissement avec un format d'avertissement.

Note: Ce problème a été rencontré en utilisant Python 2.7 sur ipython/Jupyter sur un environnement Windows 7

+0

'warn' n'a pas été retardé depuis la ligne de commande. Le message va à stderr, peut-être que votre environnement tarde à le voir. – tdelaney

+0

J'aime la façon dont warn() se comporte. Il affiche le nom du module incriminé, le numéro de la ligne de code, puis le formatage du message d'avertissement proposé en rose pour signaler à l'utilisateur que quelque chose ne va pas. Y a-t-il un moyen de contourner le problème? Idées bienvenues. (Juste essayer de rendre mon code meilleur). Note: en ce qui concerne la théorie du retard, alors que le code dans cet exemple est instable, dans mon code réel, un calcul a pris 3+ minutes à compléter, et l'avertissement est toujours apparu à la fin. S'il s'agit d'un retard, il semble que ce soit «retarder jusqu'à ce que tout le code soit terminé» plutôt que «basé sur le temps». – TMWP

+1

Qu'en est-il de flushing stderr? Cela aiderait-il de toute façon? – direprobs

Répondre

2

@direprobs fourni la réponse la plus simple à cette question dans les commentaires. Ajoutez cette ligne de code après l'appel à warn().

sys.stderr.flush()

Note: Bien qu'il provient de la bibliothèque sys, vous n'avez pas besoin d'une déclaration import parce warnings écrit à stderr et les importations déjà la bibliothèque.

Ce code peut être copié et-collé dans Python 2.7 (Jupyter Notebooks) pour exécuter rapidement et voir les effets:

Expérience Un (par rapport au code qui suit):

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

Expérience Deux:

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

Expérience trois:

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

Recherchez ce code sur GitHub plus tard. Posté ici pour aider les autres enquêtant sur la façon d'utiliser warnings.