识别Python中引发异常的数据:如何收缩此代码?
我有一个脚本,它从检查错误数据的记录文件中读取。它们可能各自抛出相同的异常,并且它们存在于同一行中。有没有一种方法可以识别哪个字段抛出了异常,而不必将其拆分为多行 玩具示例如下:识别Python中引发异常的数据:如何收缩此代码?,python,exception-handling,Python,Exception Handling,我有一个脚本,它从检查错误数据的记录文件中读取。它们可能各自抛出相同的异常,并且它们存在于同一行中。有没有一种方法可以识别哪个字段抛出了异常,而不必将其拆分为多行 玩具示例如下: a = [1] b = [2] c = [] # Oh no, imagine something happened, like some data entry error i = 0 try: z = a[i] + b[i] + c[i] except IndexError, e: print "Da
a = [1]
b = [2]
c = [] # Oh no, imagine something happened, like some data entry error
i = 0
try:
z = a[i] + b[i] + c[i]
except IndexError, e:
print "Data is missing! %s" % (str(e))
问题是,如果出现异常,用户不知道是a、b还是c丢失了数据
我想我可以这样写:
def check_data(data, index, message):
try:
return data[index]
except IndexError, e:
print "%s is missing." % (message)
raise e
a = [1]
b = [2]
c = []
i = 0
try:
z = check_data(a, i, "a") + check_data(b, i, "b") + check_data(c, i, "c")
except TypeError, e:
print "Error! We're done."
但这可能相当乏味
如果存在异常块,我还可以用什么方法来处理这种情况,以验证异常块中的每个字段?
根据以下现实情况改编的示例:
class Fork:
def __init__(self, index, fork_name, fork_goal, fork_success):
# In reality, we would do stuff here.
pass
forks = []
# In reality, we'd be reading these in and not all of the entries might exist.
fork_names = ["MatrixSpoon", "Spoon", "Spork"]
fork_goals = ["Bend", "Drink soup", "Drink soup but also spear food"]
fork_success = ["Yes!", "Yes!"]
try:
for i in range(0, len(fork_names)):
forks.append(Fork(i + 1, fork_names[i], fork_goals[i], fork_success[i]))
except IndexError, e:
print "There was a problem reading the forks! %s" % (e)
print "The field that is missing is: %s" % ("?")
当您捕捉到异常或异常时,您仍然拥有导致异常的信息 例外情况,例如:
c_1 = None
try:
c_1 = c[i]
except IndexError, e:
print "c is missing."
raise e # here you still have e and i
所以你可以这样做:
try:
a = a_1[i]
except IndexError, e:
raise Exception(e.message+'the violation is because of '+str(i))
一个更完整的解决方案。。。
如果您有兴趣了解违规的原因,例如,哪个列表短两个,您可以简单地硬编码变量:
try:
for i in range(0, len(fork_names)):
forks.append(Fork(i + 1, fork_names[i], fork_goals[i], fork_success[i]))
except IndexError, e:
print "There was a problem reading the forks! %s" % (e)
print "There are fork_names with size %s " % len(fork_names)
print "There are fork_goals with size %s " % len(fork_goals)
print "There are fork_success with size %s " % len(fork_success)
print "You tried accessing index %d" % (i+1)
好吧,我承认似乎有很多工作要做!但这是值得的,因为你必须考虑你的输入和期望输出(TDD,如果你想…)。
但这仍然很蹩脚,如果您不知道一个方法是如何调用的呢?有时候你
我们将看到:
def some_function(arg1, arg2, *args, **kwrds)
pass
因此,您可以对异常中的内容进行硬编码,在这种情况下,您可以使用sys.exc\u info
打印堆栈信息:
try:
for i in range(0, len(fork_names)):
forks.append(Fork(i + 1, fork_names[i], fork_goals[i], fork_success[i]))
except IndexError, e:
type, value, traceback = sys.exc_info()
for k, v in traceback.tb_frame.f_locals.items():
if isinstance(k, (list,tuple)):
print k, " length ", len(k)
else:
print k, v
以上将输出
Fork __main__.Fork
traceback <traceback object at 0x7fe51c7ea998>
e list index out of range
__builtins__ <module '__builtin__' (built-in)>
__file__ teststo.py
fork_names ['MatrixSpoon', 'Spoon', 'Spork']
value list index out of range
__package__ None
sys <module 'sys' (built-in)>
i 2
fork_success ['Yes!', 'Yes!']
__name__ __main__
forks [<__main__.Fork instance at 0x7fe51c7ea908>, <__main__.Fork instance at 0x7fe51c7ea950>]
fork_goals ['Bend', 'Drink soup', 'Drink soup but also spear food']
type <type 'exceptions.IndexError'>
__doc__ None
最后一句话:
这不是真正的蟒蛇。相反,您可以使用:
for idx, item enumerate(fork_names):
forks.append(Fork(idx + 1, fork_names[idx], fork_goals[idx], fork_success[idx]))
正如评论中所说,
izip
和izip_
值得研究 您可以将错误检查移动到Fork
类中,并使用itertools.izip_longest
确保在一个数据流短时间内传入/something/(实际上无
):
class Fork:
def __init__(self, index, fork_name, fork_goal, fork_success):
# first, check parameters
for name, value in (
('fork_name', fork_name),
('fork_goal', fork_goal),
('fork_success', fork_success)
):
if value is None:
raise ValueError('%s not specified' % name)
# rest of code
forks = []
# In reality, we'd be reading these in and not all of the entries might exist.
fork_names = ["MatrixSpoon", "Spoon", "Spork"]
fork_goals = ["Bend", "Drink soup", "Drink soup but also spear food"]
fork_success = ["Yes!", "Yes!"]
然后像这样改变你的循环:
for name, goal, sucess in izip_longest(fork_names, fork_goals, fork_success):
forks.append(Fork(names, goal, success))
现在,您将得到一个错误,详细说明丢失了哪个数据元素。如果缺少的元素看起来更像是
”
,而不是什么都没有,那么您可以将\uu init\uuu
中的测试从If value is None
更改为If not value
,在您介绍的情况下,您可以通过简单地检查len(a)==len len len len(b)和len(b)==len len(c)来避免每次的错误检查
开头。将验证放入函数中,然后对每个项调用它。D.R.Y.@DanielFairhead我意识到,在写了这篇文章并编辑了它的代码以反映这一点之后。还是好奇有没有更短的路!你真的应该使用izip
或izip\u longest
而不是那种讨厌的索引。预验证可以简单到assert len(set(map(len,(a,b,c)))==1
或更复杂的东西,这取决于您想要什么。知道我仍然在范围内很有用,但我想知道的是,是否有一种方法可以自动识别哪个变量缺少索引(例如:“a”),而不是索引本身,无需将其全部封装在函数中。感谢您使用此成语!
class Fork:
def __init__(self, index, fork_name, fork_goal, fork_success):
# first, check parameters
for name, value in (
('fork_name', fork_name),
('fork_goal', fork_goal),
('fork_success', fork_success)
):
if value is None:
raise ValueError('%s not specified' % name)
# rest of code
forks = []
# In reality, we'd be reading these in and not all of the entries might exist.
fork_names = ["MatrixSpoon", "Spoon", "Spork"]
fork_goals = ["Bend", "Drink soup", "Drink soup but also spear food"]
fork_success = ["Yes!", "Yes!"]
for name, goal, sucess in izip_longest(fork_names, fork_goals, fork_success):
forks.append(Fork(names, goal, success))