我有一个脚本,它从正在检查错误数据的记录文件中读取。他们可能会抛出相同的异常并且它们存在于同一行上。有没有办法确定哪个字段抛出异常而不必将其分成多行?
这里的玩具示例:
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" % ("?")
答案 0 :(得分:1)
当您捕获或异常时,您仍然可以获得有关导致该异常的信息 异常,例如:
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_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
因此,在检查上述跟踪后,您可以确定哪个列表太短。我承认,这就像拍摄调试器一样。所以,如果你想,这里是如何拍摄调试器:
try:
some_thing_that_fails()
except Exception:
import pdb; pdb.set_trace()
# if you want a better debugger that supports autocomplete and tab pressing
# to explore objects you should you use ipdb
# import ipdb; ipdb.set_trace()
for i in range(0, len(fork_names))
这不是真正的Pythonic。相反,你可以使用:
for idx, item enumerate(fork_names):
forks.append(Fork(idx + 1, fork_names[idx], fork_goals[idx], fork_success[idx]))
就像评论中所说,izip
和izip_longest
值得研究。
答案 1 :(得分:1)
您可以将错误检查移至Fork
类,并使用itertools.izip_longest
确保在一个数据流短缺时传入/ something /(真正None
):
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))
现在,您将收到一个错误,清楚地详细说明缺少哪个数据元素。如果您的缺失元素看起来更像''
,那么您可以将__init__
中的测试从if value is None
更改为if not value
。