Python:在循环数据时继续通过“RuntimeError”

问题描述

在遍历数据列表时,我将如何继续跳过 RuntimeError? 例如,假设我有如下函数 f:

t_ints = [1,2,3,4,5,6,7,8,9,10]
 
def f(x):
    for i in x:
        if i==3:
            continue
        
        elif i ==6:
            raise RuntimeError('nop')
        print(f'Processing integer {i}')
    
    print("Done")
    return

f(t_ints)

函数将打印除 3 之外的每个数字,通过 3 并继续到 4。但是,当它达到 6 时,它会产生一个名为 nop 的 RunTimeError。所以输出是:

Processing integer 1
Processing integer 2
Processing integer 4
Processing integer 5
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
c:\Users\jalmendarez.MSQT\Visual Studio Code\Test Notebooks\Test Sheet 1.py in 
     251     return
     252 
---> 253 f(t_ints)

c:\Users\jalmendarez.MSQT\Visual Studio Code\Test Notebooks\Test Sheet 1.py in f(x)
      245 
      246         elif i ==6:
----> 247             raise RuntimeError('nop')
     248         print(f'Processing integer {i}')
     249 

RuntimeError: nop

我想传递整数列表,例如上面的 t_ints,并将 for 循环中的函数应用于每个列表。

z=[
    [11,22,33,55,66,87,10],[31,53,54,[2,10,11,35]
]

所以我编写了下面的代码来循环遍历每个列表,它忽略并传递 3 并继续在列表上。但是,当它遇到 6 时,由于错误而停止并且不会继续。我尝试使用 try/except。我希望我的循环忽略 RuntimeError('nop') 并继续。

INPUT:
for i in z:
    try:
        f(i)
    except RuntimeError:
        pass
OUTPUT:
Processing integer 11
Processing integer 22
Processing integer 33
Processing integer 55
Processing integer 66
Processing integer 87
Processing integer 8
Processing integer 9
Processing integer 10
Done
Processing integer 31
Processing integer 53
Processing integer 54
Processing integer 66
Processing integer 7
Processing integer 8
Processing integer 9
Processing integer 10
Done
Processing integer 2
Processing integer 4

我想要的实际输出是:

Processing integer 11
Processing integer 22
Processing integer 33
Processing integer 55
Processing integer 66
Processing integer 87
Processing integer 8
Processing integer 9
Processing integer 10
Done
Processing integer 31
Processing integer 53
Processing integer 54
Processing integer 66
Processing integer 7
Processing integer 8
Processing integer 9
Processing integer 10
Done
Processing integer 2
Processing integer 4
Processing integer 8
Processing integer 10
Processing integer 11
Processing integer 35

关于如何使用类似于“继续”的东西的任何想法都可以克服引发的错误

——编辑—— 读这个!!

好的,这是真正的问题,因为它与我上面创建的函数没有任何关系。抱歉阅读太长,但这是必要的。

我创建了函数 f 作为示例,以查看是否可以通过 RunTimeError。这是试图解决我遇到的一个更大的问题。我有大约一百万行和 23 列的 df。有一列用于 ID。实际上只有大约 18,000 个唯一 ID。所以我创建了一个 for 循环来遍历每个唯一的 ID。在该循环中,我为每个 ID 创建了一个带有行/列的过滤数据框。使用过滤后的数据,我根据列中可用的值和我创建的一些函数来运行曲线拟合来计算指数下降曲线。这是一个简单的等式。 http://www.petrocenter.com/reservoir/DCA_theory.htm

曲线拟合运行后,我将曲线拟合求解的参数插入到我的指数下降曲线函数中。我将该函数的新值作为新列添加到 for 循环内该唯一 ID 的数据帧中。然后我将每个唯一的 ID 数据框与新的曲线拟合函数数据列一起存储在字典中。因此,我可以访问具有原始值的每个 ID 数据框,以及基于使用指数下降曲线的曲线拟合的估计值。

基本上我是曲线拟合 18,000 次。通过该过程,某些曲线拟合会产生无法求解曲线拟合的 RunTimeError。我觉得不是所有问题都解决了。我没有时间检查 18,000 个唯一 ID 数据以确保它足够干净以适合曲线。因此,我希望能够跳过出现 RunTimeError 的那些 ID 实例,并移至 for 循环中的下一个唯一 ID。

解决方法

实现问题是您的错误处理程序必须处于您希望处理错误的级别。您的代码无法处理处理循环中的错误。当您引发错误时,您的函数将退出循环,退出该函数,并引发错误以供调用程序处理。继续循环为时已晚。

如果你想在函数内继续循环,那么你必须在函数内处理异常。很简单,您根本不应该引发异常。正如您描述的所需功能一样,case 3 和 case 6 之间没有区别。

def f(x):
    for i in x:
        if i == 3 or i == 6:
            continue
        
        print(f'Processing integer {i}')
    
    print("Done")
    return

对 OP 编辑​​的回应

我认为您已经确定了您帖子的核心问题:在您发布的代码中,循环本身引发了异常;在您的实际示例中,循环调用一个函数,该函数引发异常。您需要的代码似乎很简单,如下所示:

for row in df:
    try:
        params = fit_function(row)
    exception RuntimeError:
        print(row," failed to fit.)
        continue   # if there is more row processing for a successful fit.
,

问题在于您正在捕获并仅在外部循环中处理异常。您的函数 f 对您提出的异常没有任何处理。我正在考虑您需要引发异常,否则 36 之间没有区别。第二个建议是改变你的函数 f,使其更加原子化,而不是运行在整个列表上,你可以有一个函数来测试每个元素,并在某些情况下引发异常。

不要通过 z 在循环中设置 try-except 块,而是使用 f 函数中的 try-catch。您的代码将是这样的:

def f(x):
    for i in x:
        try:
            if i==3:
                continue        
            elif i ==6:
                raise RuntimeError('NOP')
            print(f'Processing integer {i}')
        except RuntimeError:
            continue
    
    print("Done")
    return
z=[
    [11,22,33,3,55,66,87,8,9,10],[31,53,54,7,[2,4,6,10,11,35]
]
for i in z:
    try:
        f(i)
    except RuntimeError:
        pass

-------版本后提供的详细信息的代码更新-

import pandas as pd
import logging

#Setup logging to a file
logging.basicConfig(filename='example.log',encoding='utf-8',level=logging.DEBUG)

#Your fit function
def fit(filtered_df):
     #Your exponential decline fit goes here
     return fit_results

#Reading your dataset
df = pd.read_csv("all_your_data.csv")

#list of dataframes results
fit_results = []
#list of failed_ids
failed_ids = []
for unique_id in df.YOUR_ID_COLUMN.unique():
    try:
        fit_results.append(fit(df[df.YOUR_ID_COLUMN==unique_id]))
    except RuntimeError:
        failed_ids.append(unique_id)
        logging.error("{} curve fit failed".format(unique_id))