面试题答案
一键面试class ParserError(Exception):
pass
class OperatorError(ParserError):
pass
class ParenthesesError(ParserError):
pass
def parse_math_expression(expression):
try:
# 简单示例,这里可以使用更完善的语法解析逻辑
parts = expression.split()
if len(parts) != 3:
raise OperatorError("操作符错误,表达式格式应为:数字 操作符 数字")
num1, operator, num2 = parts
num1 = float(num1)
num2 = float(num2)
if operator not in ['+', '-', '*', '/']:
raise OperatorError("不支持的操作符")
if operator == '/' and num2 == 0:
raise ZeroDivisionError("除数不能为零")
if expression.count('(') != expression.count(')'):
raise ParenthesesError("括号不匹配")
if operator == '+':
return num1 + num2
elif operator == '-':
return num1 - num2
elif operator == '*':
return num1 * num2
elif operator == '/':
return num1 / num2
except (OperatorError, ParenthesesError) as e:
raise ParserError("解析错误") from e
except ZeroDivisionError as e:
raise ParserError("解析错误,出现除零错误") from e
except ValueError as e:
raise ParserError("解析错误,无法将部分转换为数字") from e
异常链在这个场景中的作用:
-
清晰的错误追踪:当
parse_math_expression
函数抛出异常时,异常链可以让调用者看到异常最初发生的原因。例如,如果在处理表达式时,由于输入的操作符不支持导致OperatorError
异常,而这个异常又被ParserError
捕获并以异常链的形式重新抛出。调用者捕获到ParserError
时,可以通过__cause__
属性追溯到最初的OperatorError
,清楚地知道是操作符的问题导致了最终的解析错误。 -
分层错误处理:通过自定义不同类型的异常,如
OperatorError
和ParenthesesError
,可以在模块内部进行精细的错误分类处理。而外层的调用者可以通过捕获更通用的ParserError
,同时又能从异常链中获取具体的错误细节,实现了分层的错误处理机制,提高了代码的可读性和维护性。