Python中try-catch-raise异常子句的两次运行行为



在下面的最小示例中,我用自己的方法safe_apply包装了pandas.DataFrame.apply方法。该方法与普通apply有两个不同之处:

  1. 不是在NDFrame中返回值,而是将它们附加到列表results中。
  2. 如果捕获到异常,在引发错误并终止执行之前打印results

代码如下:

from pandas.core.frame import DataFrame, Series
import pandas as pd
def safe_apply(df, func, **kwargs):
    results = []
    def new_func(srs):
        try:
            results.append(func(srs))
        except Exception as e:
            print(results)
            raise
    df.apply(new_func, **kwargs)
    return results
DataFrame.safe_apply = safe_apply
def f(srs):
    if (pd.notnull(srs['lat'])) & (pd.notnull(srs['long'])):
        return srs['lat'] + srs['long']
    else:
        raise ValueError

ex = pd.DataFrame({'lat': [1, 2, None], 'long': [1, 2, None]}, index=['A', 'B', 'C'])
ex.safe_apply(f, axis='columns')

当我执行这个时,我除了将函数f应用于ex的前两行,然后在第三行失败的结果:[2.0, 4.0]中的print,然后是ValueError

相反,我得到一个ValueError两行输出:
[2.0, 4.0]
[2.0, 4.0, 2.0, 4.0]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-382c07ef0919> in <module>()
     26         raise ValueError
     27 
---> 28 ex.safe_apply(f, axis='columns')
<ipython-input-1-382c07ef0919> in safe_apply(df, func, **kwargs)
     12             raise
     13 
---> 14     df.apply(new_func, **kwargs)
     15 
     16     return results
C:UsersAlexAnaconda3libsite-packagespandascoreframe.py in apply(self, func, axis, broadcast, raw, reduce, args, **kwds)
   4059                     if reduce is None:
   4060                         reduce = True
-> 4061                     return self._apply_standard(f, axis, reduce=reduce)
   4062             else:
   4063                 return self._apply_broadcast(f, axis)
C:UsersAlexAnaconda3libsite-packagespandascoreframe.py in _apply_standard(self, func, axis, ignore_failures, reduce)
   4155             try:
   4156                 for i, v in enumerate(series_gen):
-> 4157                     results[i] = func(v)
   4158                     keys.append(v.name)
   4159             except Exception as e:
<ipython-input-1-382c07ef0919> in new_func(srs)
      7     def new_func(srs):
      8         try:
----> 9             results.append(func(srs))
     10         except Exception as e:
     11             print(results)
<ipython-input-1-382c07ef0919> in f(srs)
     24         return srs['lat'] + srs['long']
     25     else:
---> 26         raise ValueError
     27 
     28 ex.safe_apply(f, axis='columns')
ValueError: occurred at index C

表示代码到达异常子句,打印出results,然后,不是抛出错误并停止,而是以某种方式再次运行函数(?)。

为什么会出现这种情况?

请参阅文档字符串的注释部分,特别是

在当前的实现中,apply对第一列/行调用两次func,以决定它是否可以采用快速或缓慢的代码路径。如果func有副作用,这会导致意想不到的行为,因为它们将对第一列/行生效两次。

最新更新