【问题标题】:python map exception continue mapping executionpython map异常继续映射执行
【发布时间】:2015-12-23 04:03:22
【问题描述】:

下面的例子很简单。我想用一个可以引发异常的函数来执行 ma​​p()。举个例子会更清楚:

number_list = range(-2,8)

def one_divide_by(n):
    return 1/n

try:
    for number, divide in zip(number_list, map(one_divide_by, number_list)):
        print("%d : %f" % (number, divide))
except ZeroDivisionError:
    # Execution is stopped. I want to continue mapping
    pass

当我执行这段代码时,我得到:

-2 : -0.500000
-1 : -1.000000

这是由于我的列表中的 0。我不想删除这个 0 (因为在实际情况下,我不能先知道我是否会得到异常)。 你知道如何在异常发生后继续映射

【问题讨论】:

  • 如果你知道用什么值代替'infinite'然后使用try: return 1/n; except ZeroDivisionError: return yourvalue

标签: python dictionary exception-handling python-3.4


【解决方案1】:

另一种选择是定义一个辅助函数,该函数接受如下异常的处理程序:

def map_e(function, *iterables, on_exception=None):
    for elements in zip(*iterables):
        try:
            yield function(*elements)
        except Exception as e:
            yield on_exception(elements, exception=e) \
                if callable(*on_exception) \
                else None


list_a = [1,  2, 5, 1]
list_b = [2, -2, 6, 6]
list_c = [2,  1, 0, 8]


def sum_then_divide(a, b, c):
    return (a + b) / c


def none_on_exception(*args, **kwargs):
    return None


result = list(
    map_e(
        sum_then_divide,
        list_a,
        list_b,
        list_c,
        on_exception=none_on_exception
    )
)

print(result)

无需在主函数中处理异常,也无需添加外部库。

【讨论】:

    【解决方案2】:

    如果你可以替换map而不是改变你的函数定义one_divide_by,我会推荐more_itertools.map_except

    from more_itertools import map_except
    
    number_list = range(-2,8)
    
    def one_divide_by(n):
        return 1/n
    
    for number, divide in map_except(
            lambda number: (number, one_divide_by(number)),
            number_list,
            ZeroDivisionError
    ):
        print(number, ':', divide)
    

    按预期打印:

    -2 : -0.5
    -1 : -1.0
    1 : 1.0
    2 : 0.5
    3 : 0.3333333333333333
    4 : 0.25
    5 : 0.2
    6 : 0.16666666666666666
    7 : 0.14285714285714285
    

    函数more_itertools.map_except 接受一个函数、一个可迭代作为输入(就像内置的map)和预期的异常。如果在映射过程中引发这些异常之一,则简单地跳过该元素。

    可以使用pip install more-itertools(对于 pip 用户)或 conda install -c conda-forge more-itertools(对于 Conda 用户)安装此软件包。

    【讨论】:

      【解决方案3】:

      如果引发ZeroDivisionError,你可以在你的函数中(而不是在for循环中)捕获异常并返回None(或任何你选择的):

      def one_divide_by(n):
          try:
              return 1/n
          except ZeroDivisionError:
              return None
      

      如果你选择return None,你需要调整你的格式字符串; None 不能用%f 格式化。

      您可以返回的其他值(并且与您的字符串格式兼容)是float('inf')(或float('-inf'),取决于您的分子符号)或float('nan') - "inf inity”或“not a number”。

      here 你会发现使用float('inf') 的一些注意事项。

      【讨论】:

      • 我认为返回float('nan') 可能是这里最好的选择。但是我想应该提一下,你需要使用math.isnan()来测试nan
      【解决方案4】:

      您可以在函数内移动try/except 块。示例 -

      def one_divide_by(n):
          try:
              return 1/n
          except ZeroDivisionError:
              return 0   #or some other default value.
      

      然后正常调用它,没有 try/except 块 -

      for number, divide in zip(number_list, map(one_divide_by, number_list)):
          print("%d : %f" % (number, divide))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多