Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从函数中收集警告的最具python风格的方法_Python_Python 3.x - Fatal编程技术网

从函数中收集警告的最具python风格的方法

从函数中收集警告的最具python风格的方法,python,python-3.x,Python,Python 3.x,考虑一个非常简单的函数: def generate_something(data): if data is None: raise Exception('No data!') return MyObject(data) 它的输出基本上是我想要创建的对象的实例,或者如果函数无法创建对象,则是异常。我们可以说输出是二进制的,因为它要么成功(并返回一个对象),要么不成功(并返回一个异常) 处理第三种状态,即“成功但有一些警告”的最具python风格的方式是什么 返回

考虑一个非常简单的函数:

def generate_something(data):
    if data is None:
        raise Exception('No data!')

    return MyObject(data)
它的输出基本上是我想要创建的对象的实例,或者如果函数无法创建对象,则是异常。我们可以说输出是二进制的,因为它要么成功(并返回一个对象),要么不成功(并返回一个异常)

处理第三种状态,即“成功但有一些警告”的最具python风格的方式是什么


返回元组是处理此问题的唯一方法,还是可以从函数中广播或产生警告,并从调用方捕获它们?

您可以返回异常列表(或自定义异常),其中有问题供以后处理:

class MyWarning(Warning):
    pass

def generate_something(data):
    warnings = []
    if data is None:
        raise Exception("No data!")

    if data.value_1 == 2:
        warnings.append(MyWarnin('Hmm, value_1 is 2'))    

    if data.value_2 == 1:
        warnings.append(MyWarning('Hmm, value_2 is 1'))    

    return MyObject(data), warnings
然后举例来说:

def handle_warnings(warnings):
    for w in warnings:
        try:
            raise w
        except MyWarning:
            ...
        except AttributeError: #in case you want to handle other type of errors
            ...
内置选项: Python在模块中实现了内置的警告机制。问题是,
警告
维护一个全局值,这可能会无意中导致函数抛出的警告被抑制。下面是问题的演示:

import warnings

def my_func():
    warnings.warn('warning!')

my_func()  # prints "warning!"

warnings.simplefilter("ignore")
my_func()  # prints nothing
如果要使用
警告
而不考虑这一点,则可以使用收集列表中所有抛出的警告:

with warnings.catch_warnings(record=True) as warning_list:
    warnings.warn('warning 3')

print(warning_list)  # output: [<warnings.WarningMessage object at 0x7fd5f2f484e0>]
  • 将警告处理程序传递给函数

    如果要在生成警告时立即处理这些警告,可以重写函数以接受警告处理程序作为参数:

    def example_func(warning_handler=lambda w: None):
        if ...:
            warning_handler('warning!')
    
        return result
    
    
    def my_handler(w):
        print('warning', repr(w), 'was produced')
    
    result = example_func(my_handler)
    
    • (python 3.7+)

      在python 3.7中,我们得到了一个模块,它允许我们基于上下文管理器实现更高级别的警告机制:

      import contextlib
      import contextvars
      import warnings
      
      
      def default_handler(warning):
          warnings.warn(warning, stacklevel=3)
      
      _warning_handler = contextvars.ContextVar('warning_handler', default=default_handler)
      
      
      def warn(msg):
          _warning_handler.get()(msg)
      
      
      @contextlib.contextmanager
      def warning_handler(handler):
          token = _warning_handler.set(handler)
          yield
          _warning_handler.reset(token)
      
      用法示例:

      def my_warning_handler(w):
          print('warning', repr(w), 'was produced')
      
      with warning_handler(my_warning_handler):
          warn('some problem idk')  # prints "warning 'some problem idk' was produced"
      
      warn(Warning('another problem'))  # prints "Warning: another problem"
      
      注意事项:目前,
      contextvars
      不支持生成器。(相关。)以下示例之类的内容无法正常工作:

      def gen(x):
          with warning_handler(x):
              for _ in range(2):
                  warn('warning!')
                  yield
      
      g1 = gen(lambda w: print('handler 1'))
      g2 = gen(lambda w: print('handler 2'))
      
      next(g1)  # prints "handler 1"
      next(g2)  # prints "handler 2"
      next(g1)  # prints "handler 2"
      

      >强>没有代码> CONTEXVARS (Python FWW有,但我不认为这是你要寻找的警告机制。你能用Python的标准<代码>警告< /代码>模块来解释什么是不够的吗?如Aran所建议的?没有这些信息,我认为这个问题不清楚没有什么“错”。使用“措辞”模块,但如果我想要一个警告列表,这不是我从中得到的。它会写入stderror,不会返回警告列表。这只是一个模糊的推测。但如果我遇到这样一种情况,即函数需要报告大量的状态信息,我会怀疑该函数是否做得太多或不够。也就是说(a)是否有可能将其拆分为总是导致成功或失败的“原子”操作?或者(b)调用者需要如何处理各种状态,是否有可能将这种行为封装到函数本身中,这样上游的状态就无关紧要了?附录:最后一条评论假设调用者在正常操作期间确实需要状态信息。如果他们不需要,那就“很高兴拥有”对于诊断,您可能希望使用调试标志,或者可能将警告累积到作为可选关键字参数传入的列表中。然后调用方可以使用该函数而不关心警告,而将它们放入返回值会强制它们显式地分解返回值。子分类
      警告
      将更有意义
      
      def my_warning_handler(w):
          print('warning', repr(w), 'was produced')
      
      with warning_handler(my_warning_handler):
          warn('some problem idk')  # prints "warning 'some problem idk' was produced"
      
      warn(Warning('another problem'))  # prints "Warning: another problem"
      
      def gen(x):
          with warning_handler(x):
              for _ in range(2):
                  warn('warning!')
                  yield
      
      g1 = gen(lambda w: print('handler 1'))
      g2 = gen(lambda w: print('handler 2'))
      
      next(g1)  # prints "handler 1"
      next(g2)  # prints "handler 2"
      next(g1)  # prints "handler 2"
      
      import contextlib
      import threading
      import warnings
      
      
      def default_handler(warning):
          warnings.warn(warning, stacklevel=3)
      
      _local_storage = threading.local()
      _local_storage.warning_handler = default_handler
      
      
      def _get_handler():
          try:
              return _local_storage.warning_handler
          except AttributeError:
              return default_handler
      
      
      def warn(msg):
          handler = _get_handler()
          handler(msg)
      
      
      @contextlib.contextmanager
      def warning_handler(handler):
          previous_handler = _get_handler()
          _local_storage.warning_handler = handler
      
          yield
      
          _local_storage.warning_handler = previous_handler