Python try-except 块的 DRY 方法?
A DRY approach to Python try-except blocks?
Objective: 我有几行代码,每行代码都会产生相同类型的错误,并保证相同类型的响应。如何防止 try-except 块出现 'do not repeat yourself' 问题。
背景:
我使用 ReGex 从文本文件中抓取格式不正确的数据,并将其输入到自定义对象的字段中。该代码工作得很好,除非该字段留空,在这种情况下它会抛出错误。
我在 try-except 块中处理这个错误。如果错误,则在对象的字段中插入一个空格(即“”)。
问题是它将易读、漂亮、Python 代码变成了一堆 try-except 块,每个块都做完全相同的事情。这是 'do not repeat yourself'(a.k.a。干燥)违规行为。
代码:
之前:
sample.thickness = find_field('Thickness', sample_datum)[0]
sample.max_tension = find_field('Maximum Load', sample_datum)[0]
sample.max_length = find_field('Maximum Extension', sample_datum)[0]
sample.test_type = sample_test
之后:
try:
sample.thickness = find_field('Thickness', sample_datum)[0]
except:
sample.thickness = ''
try:
sample.max_tension = find_field('Maximum Load', sample_datum)[0]
except:
sample.max_tension = ''
try:
sample.max_length = find_field('Maximum Extension', sample_datum)[0]
except:
sample.max_length = ''
try:
sample.test_type = sample_test
except:
sample.test_type = ''
我需要什么:
有什么 Pythonic 的写法吗?在某些块中,如果这些行中的任何一行出现索引超出范围错误(表明该字段为空白,并且 ReGex 无法 return 任何内容),我可以在示例字段中插入一个空白。
您可以反复使用任意数量的 except
块,处理不同类型的异常。在同一个 try/catch 块中有多个语句也没有错。
try:
doMyDangerousThing()
except ValueError:
print "ValueError!"
except HurrDurrError:
print "hurr durr, there's an error"
try:
doMyDangerousThing()
doMySecondDangerousThing()
except:
print "Something went wrong!"
从中提取一个函数怎么样?
def maybe_find_field(name, datum):
try:
return find_field(name, datum)[0]
except IndexError: # Example of specific exception to catch
return ''
sample.thickness = maybe_find_field('Thickness', sample_datum)
sample.max_tension = maybe_find_field('Maximum Load', sample_datum)
sample.max_length = maybe_find_field('Maximum Extension', sample_datum)
sample.test_type = sample_test
顺便说一句,不要简单地使用 except:
捕获所有可能的异常,除非这确实是您想要做的。捕获所有内容可能会隐藏实现错误,并且以后很难调试。只要有可能,将您的 except
案例绑定到您需要的特定异常。
当你发现自己在重复代码时,将其封装在一个函数中。在这种情况下,创建一个函数来为您处理异常。
def try_find_field(field_name, datum, default_value):
try:
return find_field(field_name, datum)[0]
except:
return default_value
像这样的事情怎么样:
def exception_handler(exception_class):
logger = logging.getLogger('app_error')
logger.error(exception_class)
exception_name = exception_class.__name__
if exception_name == 'AuthenticationError':
raise AuthenticationError
elif exception_name == 'AuthorizationError':
raise AuthorizationError
elif exception_name == 'ConnectionError':
raise ConnectionError
else:
raise GenericError
def call_external_api()
try:
result = http_request()
except Exception as e:
exception_handler(exception_class=type(e))
不太符合问题,但是 Google 派我来这里,所以其他人可能会来。
我在两个单独的 Django 视图中有 post
函数,它们调用相似的后端函数并需要相同的异常处理。
我通过提取整个 except:
-tree 并将其粘贴到装饰器中解决了这个问题。
之前:
# twice this
def post(request):
try:
return backend_function(request.post)
except ProblemA as e:
return Response("Problem A has occurred, try this to fix it.", status=400)
except ProblemB as e:
return Response("Problem B has occurred, try this to fix it.", status=400)
except ProblemC as e:
return Response("Problem C has occurred, try this to fix it.", status=400)
except ProblemD as e:
return Response("Problem D has occurred, try this to fix it.", status=400)
之后:
# once this
def catch_all_those_pesky_exceptions(original_function):
def decorated(*args, **kwargs):
try:
return original_function(*args, **kwargs)
except ProblemA as e:
return Response("Problem A has occurred, try this to fix it.", status=400)
except ProblemB as e:
return Response("Problem B has occurred, try this to fix it.", status=400)
except ProblemC as e:
return Response("Problem C has occurred, try this to fix it.", status=400)
except ProblemD as e:
return Response("Problem D has occurred, try this to fix it.", status=400)
return decorated
# twice this - note the @decorator matching the above function.
@catch_all_those_pesky_exceptions
def post(request):
return backend_function(request.post)
现在我可以在一个地方添加更多的异常处理。
Objective: 我有几行代码,每行代码都会产生相同类型的错误,并保证相同类型的响应。如何防止 try-except 块出现 'do not repeat yourself' 问题。
背景:
我使用 ReGex 从文本文件中抓取格式不正确的数据,并将其输入到自定义对象的字段中。该代码工作得很好,除非该字段留空,在这种情况下它会抛出错误。
我在 try-except 块中处理这个错误。如果错误,则在对象的字段中插入一个空格(即“”)。
问题是它将易读、漂亮、Python 代码变成了一堆 try-except 块,每个块都做完全相同的事情。这是 'do not repeat yourself'(a.k.a。干燥)违规行为。
代码:
之前:
sample.thickness = find_field('Thickness', sample_datum)[0]
sample.max_tension = find_field('Maximum Load', sample_datum)[0]
sample.max_length = find_field('Maximum Extension', sample_datum)[0]
sample.test_type = sample_test
之后:
try:
sample.thickness = find_field('Thickness', sample_datum)[0]
except:
sample.thickness = ''
try:
sample.max_tension = find_field('Maximum Load', sample_datum)[0]
except:
sample.max_tension = ''
try:
sample.max_length = find_field('Maximum Extension', sample_datum)[0]
except:
sample.max_length = ''
try:
sample.test_type = sample_test
except:
sample.test_type = ''
我需要什么:
有什么 Pythonic 的写法吗?在某些块中,如果这些行中的任何一行出现索引超出范围错误(表明该字段为空白,并且 ReGex 无法 return 任何内容),我可以在示例字段中插入一个空白。
您可以反复使用任意数量的 except
块,处理不同类型的异常。在同一个 try/catch 块中有多个语句也没有错。
try:
doMyDangerousThing()
except ValueError:
print "ValueError!"
except HurrDurrError:
print "hurr durr, there's an error"
try:
doMyDangerousThing()
doMySecondDangerousThing()
except:
print "Something went wrong!"
从中提取一个函数怎么样?
def maybe_find_field(name, datum):
try:
return find_field(name, datum)[0]
except IndexError: # Example of specific exception to catch
return ''
sample.thickness = maybe_find_field('Thickness', sample_datum)
sample.max_tension = maybe_find_field('Maximum Load', sample_datum)
sample.max_length = maybe_find_field('Maximum Extension', sample_datum)
sample.test_type = sample_test
顺便说一句,不要简单地使用 except:
捕获所有可能的异常,除非这确实是您想要做的。捕获所有内容可能会隐藏实现错误,并且以后很难调试。只要有可能,将您的 except
案例绑定到您需要的特定异常。
当你发现自己在重复代码时,将其封装在一个函数中。在这种情况下,创建一个函数来为您处理异常。
def try_find_field(field_name, datum, default_value):
try:
return find_field(field_name, datum)[0]
except:
return default_value
像这样的事情怎么样:
def exception_handler(exception_class):
logger = logging.getLogger('app_error')
logger.error(exception_class)
exception_name = exception_class.__name__
if exception_name == 'AuthenticationError':
raise AuthenticationError
elif exception_name == 'AuthorizationError':
raise AuthorizationError
elif exception_name == 'ConnectionError':
raise ConnectionError
else:
raise GenericError
def call_external_api()
try:
result = http_request()
except Exception as e:
exception_handler(exception_class=type(e))
不太符合问题,但是 Google 派我来这里,所以其他人可能会来。
我在两个单独的 Django 视图中有 post
函数,它们调用相似的后端函数并需要相同的异常处理。
我通过提取整个 except:
-tree 并将其粘贴到装饰器中解决了这个问题。
之前:
# twice this
def post(request):
try:
return backend_function(request.post)
except ProblemA as e:
return Response("Problem A has occurred, try this to fix it.", status=400)
except ProblemB as e:
return Response("Problem B has occurred, try this to fix it.", status=400)
except ProblemC as e:
return Response("Problem C has occurred, try this to fix it.", status=400)
except ProblemD as e:
return Response("Problem D has occurred, try this to fix it.", status=400)
之后:
# once this
def catch_all_those_pesky_exceptions(original_function):
def decorated(*args, **kwargs):
try:
return original_function(*args, **kwargs)
except ProblemA as e:
return Response("Problem A has occurred, try this to fix it.", status=400)
except ProblemB as e:
return Response("Problem B has occurred, try this to fix it.", status=400)
except ProblemC as e:
return Response("Problem C has occurred, try this to fix it.", status=400)
except ProblemD as e:
return Response("Problem D has occurred, try this to fix it.", status=400)
return decorated
# twice this - note the @decorator matching the above function.
@catch_all_those_pesky_exceptions
def post(request):
return backend_function(request.post)
现在我可以在一个地方添加更多的异常处理。