I have code where I am parsing a JSON feed.
我有解析JSON提要的代码。
For each array I have code that looks like:
对于每个数组,我都有如下代码:
for node in parse_me:
# It's important that one iteration failing doesn't cause all iterations to fail.
try:
i = node['id'] # KeyError?
function_that_needs_int (i) # TypeError?
# possibly other stuff
except Exception as e:
LogErrorMessage ('blah blah blah {} in node {}'.fmt(e, node))
I do not like that this makes my for loops double-nested just because I need to stop exceptions from aborting the loop. Is there a way to flatten this code?
我不喜欢这样做,因为我需要阻止异常中止循环。有没有办法使这段代码变平?
2 个解决方案
#1
5
Then you should do things like
那么你应该做一些类似的事情
def iterate_safe(parse_me, message, action):
for node in parse_me:
try:
action(node)
except Exception as e:
LogErrorMessage(message.fmt(e, node))
and then call it like
然后这样称呼它
def action(node):
do_whatever_must_be_done_with(node)
iterate_safe(parse_me, action, 'blah blah blah {} in node {}')
iterate_safe(parse_me, other_action, 'spam ham {} in node {}')
#2
1
EDIT: The original question seemed to imply that the entire parse operation was in one giant for
-loop; my answer has been modified to reflect comments below.
编辑:最初的问题似乎暗示了整个解析操作是一个巨大的for循环;我的回答被修改以反映下面的评论。
Instead of writing multiple for
-loops, each of which must include a try
/catch
block, write functions describing what must be done within the loops, and write a decorator to apply to them that will surround each one with the for
-loop and the try
/catch
logging logic. This is a bit like glglgl's solution, but a bit more Pythonic (in my opinion). For example:
不是编写多个for循环,每个for循环必须包含一个try/catch块,而是编写描述循环中必须完成的操作的函数,并编写一个decorator来应用它们,它将用for循环和try/catch日志记录逻辑包围每个for循环。这有点像glglgl的解决方案,但更像毕达哥拉斯(在我看来)。例如:
def apply_to_nodes_and_log_errs(node_visit_func):
def safe_iterating_visitor(nodes_to_parse):
for node in nodes_to_parse:
try:
node_visit_func(node)
except StandardError as e:
LogErrorMessage ('blah blah blah {} in node {}'.fmt(e, node))
return safe_iterating_visitor
@apply_to_nodes_and_log_errs
def action_one(node):
# ... "lots of stuff" :D
@apply_to_nodes_and_log_errs
def action_two(node):
# different stuff
If you'd rather break the decorator into chunks:
如果你愿意把装饰者分成几块:
def iterate_over_nodelist(node_visit_func):
def iterating_visitor(nodes_to_parse):
for node in nodes_to_parse:
node_visit_func(node)
return iterating_visitor
def safely_visit_log_errs(node_visit_func):
def safe_logging_visitor(node_to_visit):
try:
node_visit_func(node)
except StandardError as e:
LogErrorMessage ('blah blah blah {} in node {}'.fmt(e, node))
return safe_logging_visitor
def apply_to_nodes_and_log_errs(node_visit_func):
return iterate_over_nodelist(safely_visit_log_errs(node_visit_func))
# ... write visit functions
This could be further improved using functools.wraps
.
这可以通过使用功能工具进行进一步的改进。
Note that although this may look a little ugly if your standard is "use as few levels of indentation as possible," it's actually quite Pythonic; there's really no way to avoid quite a few indentation levels when writing decorators.
请注意,如果您的标准是“尽可能少地使用缩进”,这可能看起来有点难看,但实际上它是非常python化的;在编写decorator时,确实无法避免相当多的缩进级别。
Finally, note that change from Exception
to StandardError
, which I still strongly recommend.
最后,请注意从异常到标准镜的更改,我仍然强烈建议这样做。
#1
5
Then you should do things like
那么你应该做一些类似的事情
def iterate_safe(parse_me, message, action):
for node in parse_me:
try:
action(node)
except Exception as e:
LogErrorMessage(message.fmt(e, node))
and then call it like
然后这样称呼它
def action(node):
do_whatever_must_be_done_with(node)
iterate_safe(parse_me, action, 'blah blah blah {} in node {}')
iterate_safe(parse_me, other_action, 'spam ham {} in node {}')
#2
1
EDIT: The original question seemed to imply that the entire parse operation was in one giant for
-loop; my answer has been modified to reflect comments below.
编辑:最初的问题似乎暗示了整个解析操作是一个巨大的for循环;我的回答被修改以反映下面的评论。
Instead of writing multiple for
-loops, each of which must include a try
/catch
block, write functions describing what must be done within the loops, and write a decorator to apply to them that will surround each one with the for
-loop and the try
/catch
logging logic. This is a bit like glglgl's solution, but a bit more Pythonic (in my opinion). For example:
不是编写多个for循环,每个for循环必须包含一个try/catch块,而是编写描述循环中必须完成的操作的函数,并编写一个decorator来应用它们,它将用for循环和try/catch日志记录逻辑包围每个for循环。这有点像glglgl的解决方案,但更像毕达哥拉斯(在我看来)。例如:
def apply_to_nodes_and_log_errs(node_visit_func):
def safe_iterating_visitor(nodes_to_parse):
for node in nodes_to_parse:
try:
node_visit_func(node)
except StandardError as e:
LogErrorMessage ('blah blah blah {} in node {}'.fmt(e, node))
return safe_iterating_visitor
@apply_to_nodes_and_log_errs
def action_one(node):
# ... "lots of stuff" :D
@apply_to_nodes_and_log_errs
def action_two(node):
# different stuff
If you'd rather break the decorator into chunks:
如果你愿意把装饰者分成几块:
def iterate_over_nodelist(node_visit_func):
def iterating_visitor(nodes_to_parse):
for node in nodes_to_parse:
node_visit_func(node)
return iterating_visitor
def safely_visit_log_errs(node_visit_func):
def safe_logging_visitor(node_to_visit):
try:
node_visit_func(node)
except StandardError as e:
LogErrorMessage ('blah blah blah {} in node {}'.fmt(e, node))
return safe_logging_visitor
def apply_to_nodes_and_log_errs(node_visit_func):
return iterate_over_nodelist(safely_visit_log_errs(node_visit_func))
# ... write visit functions
This could be further improved using functools.wraps
.
这可以通过使用功能工具进行进一步的改进。
Note that although this may look a little ugly if your standard is "use as few levels of indentation as possible," it's actually quite Pythonic; there's really no way to avoid quite a few indentation levels when writing decorators.
请注意,如果您的标准是“尽可能少地使用缩进”,这可能看起来有点难看,但实际上它是非常python化的;在编写decorator时,确实无法避免相当多的缩进级别。
Finally, note that change from Exception
to StandardError
, which I still strongly recommend.
最后,请注意从异常到标准镜的更改,我仍然强烈建议这样做。