我正在循环遍历python程序中的列表。对于列表中的每个项目,我从另一个python文件中调用一个函数,该文件在当前程序中导入。具有被调用函数的文件具有自己的异常处理。我希望调用程序在被调用程序中发生异常时跳过循环的当前迭代,并继续循环的下一次迭代。我尝试在调用程序的except子句中使用import B
for item in list:
try :
B.some_function(item)
except Exception as err:
continue
关键字。但它并没有像我预期的那样发挥作用。
程序的结构是这样的 -
A.py
s = "{0} " \
"{1} " \
"{2}" \
.format("Hello", "world", "from a multiline string")
print(s)
请注意, B.py 文件包含多个具有自己的异常处理功能。上面的代码在第一个异常发生时终止。我想让它继续循环的下一次迭代。
为什么会这样?
答案 0 :(得分:1)
听起来你需要A
和B
之间的一些额外信号。它需要是B
的透明添加,不会干扰它的当前行为。基本上向B
的范围添加一些可以通过其异常处理修改的内容,并且可以由A
查询。
取决于B
中的其他内容 - 我认为模块级变量用作B
中的try / except可能会更改的标记以及A
中的try / except可以查询。
<强> B.py 强>
#exception handling toggles this flag
exception_handled = False
def f():...
def g():...
...
<强> A.py 强>
import B
for item in list:
try :
B.some_function(item)
if B.exception_handled:
#reset flag
B.exception_handled = False
raise Exception
# or just
#continue
except Exception as err:
B.exception_handled = False
continue
或者您可以向B
函数添加属性/标记,异常处理可以切换,A
可以查询。
<强> B.py 强>
#decorator to add flag to functions
def add_attr(func):
func.exception_handled = False
return func
@add_attr
def f():...
@add_attr
def g():...
...
#exception handler modifies a function attribute
#func.exception_handled = True
<强> A.py 强>
import B
for item in list:
try :
B.some_function(item)
if B.some_function.exception_handled:
# reset flag
B.some_function.exception_handled = False
raise Exception
# or just
#continue
except Exception as err:
B.some_function.exception_handled = False
continue
我想它可能会变得更加精致,如
B
中的模块级字典,其中包含每个B
函数的状态。
<强> B.py 强>
exceptions = {}
def register(func):
exceptions[func.__name__] = False
return func
@register
def f():...
@register
def g():...
#exception handling -> exceptions[f] = True or exceptions[current_func] = True
然后A
查询字典:
if any(B.exceptions.values()):
#reset the flags
for k in B.exceptions:
B.exceptions[k] = False
#raise exception
#just continue
对于最后两个解决方案,您可以使用sys,traceback和/或inspect模块确定函数名称。获得名称后,您可以根据需要通过globals()或locals()获取对函数本身的引用。以下是B.py
中的内容的快速示例。
from pprint import pprint
import sys, inspect, traceback
exceptions = {}
def g():
try:
return 1 / 0
except ZeroDivisionError as e:
#find the function name as a string from the traceback
typ, val, tb = sys.exc_info()
# one way
func_name0 = traceback.extract_tb(tb)[-1][-2]
# another way via the frame object:
# you have to get to the frame that caused the exception
tb_x = tb
while tb_x.tb_next is not None:
tb_x = tb_x.tb_next
func_name1 = tb_x.tb_frame.f_code.co_name
print func_name0, func_name1
# toggle the exeptions dictionary
exceptions[func_name0] = True
# get a reference to the function after finding the name
func = globals()[func_name0]
# and toggle its flag attribute
func.exception_handled = True
# what can you do with inspect
# inspect.trace()[-1] contains the same frame object as tb_x
pprint(inspect.trace()[-1])
func_name2 = inspect.trace()[-1][-3]
从2.7代码的打印语句中可以看出,我在这台机器上没有3.x. 3.x中有一些新方法可用于追溯和检查可能有用的模块。
答案 1 :(得分:0)
如果B.some_function(item)
从不引发单个异常,则try
块无意义。
你永远无法发现B.some_function
执行的任何故障。
因此,您需要B.some_function
来实际引发错误。
所以,“为什么会这样?”只是因为“[some_function
]有自己的异常处理”。
如果您有权访问其代码,则应对其进行编辑,以便在需要时实际引发错误。
如果您无法访问其代码,则有两种可能:
如果它是1,好的,你需要做的就是找到并理解如何检测错误。 如果它是2,那么,你不能(再次,假设你不能编辑代码)。 如果是这样,函数的使用方式可能与您尝试使用它的方式不同。
由于您确实有权对some_function
进行细微更改,因此这是一个不应该破坏任何依赖它的代码的修复程序,同时允许您检查是否发生了错误。
首先,将关键字参数添加到B.some_function
,默认为None
。
这样,任何调用它的代码都不会中断,因为它将被设置而不被显式传递。
此参数将表现为标志:如果它被引发,则发生错误。
这里,“raise”表示其内部值设置为True
。
如果没有标志作为参数传递,则行为保持不变。
"""B.py"""
def some_function(arguments..., myFlag=None):
# stuff
if error_happens():
if myFlag is not None:
myFlag.value = True
# stuff
现在,在A.py
中,定义一个标志类。
不能使用简单的布尔值,因为它需要通过引用传递给B.some_function
,并由它进行修改。
MyFlag
个实例具有value
属性,初始化时设置为False
,当标志需要发出事件发生时,将设置为True
。
"""A.py"""
class MyFlag:
def __init__(self):
self.value = False
# Just for more comfort: allows to write "if myFlag: ..."
def __bool__(self):
return self.value
# Create a flag that will be down unless an error was raised
errorCaught = MyFlag()
# Call some_function and pass the flag as myFlag keyword argument
B.some_function(arguments.., myFlag=errorCaught)
# If errorCaught is True, then errorCaught.value is True as well,
# hence an error was detected
if errorCaught:
print("An error got raised")
答案 2 :(得分:0)
在下面的示例中,我在Module B.py中定义了一个自定义异常 MyException ,并在函数some_function中引发了。在模块A.py中,我使用try和catch over调用b.py模块的some_function
<强> A.py 强>
from B import some_function , MyException
lst = [0,2,4,1,3] # for example take it as list of number
for item in lst:
try :
some_function(item)
except MyException as err:
print "error"
continue
<强> B.py 强>
class MyException(Exception):
pass
def some_function(val):
""" this function raise exception when val equal to 1 """
if val == 1: # for example raise exception when input is 1
raise MyException
else:
print val
<强>输出强>
0
2
4
error
3