自定义异常类中super().__init__()的作用及有无该行的差异
问题场景
我定义了一个自定义异常类,原本以为自己写的error_message_details函数已经处理了错误消息的生成,疑惑为什么必须调用父类Exception的构造函数super().__init__(error_message)。测试发现去掉这行后错误消息完全不打印,保留则正常运行,想搞懂背后的原理。
我的自定义异常代码:
class CustomException(Exception): def __init__(self, error_message, error_detail:sys): super().__init__(error_message) # 调用父类构造函数 self.error_message = error_message_details(error_message,error_detail) def __str__(self): return self.error_message
辅助函数error_message_details:
def error_message_details(error, error_detail:sys): _,_,exc_tb = error_detail.exc_info() # 从解释器获取异常信息 file_name = exc_tb.tb_frame.f_code.co_filename lineNo = exc_tb.tb_lineno error_message = "error occured in script [{0}] on line number [{1}]; error message [{2}]".format( file_name, lineNo, str(error) ) return error_message
有无super().__init__的差异
- 保留该行:异常触发后能正常打印自定义的错误信息,同时Python的异常处理机制能完整识别这个异常对象的所有属性。
- 去掉该行:虽然重写了
__str__方法返回自定义消息,但在部分场景下(比如解释器默认的异常输出、依赖标准异常属性的工具),错误消息会无法正常输出,甚至出现无消息的情况。
背后的原理
父类Exception的内部状态初始化
Python的Exception类本身维护了args等核心属性,__init__方法会把传入的error_message存入这些属性——这是Python异常系统默认识别的消息来源。如果不调用父类构造函数,这些属性会处于未初始化的状态。异常处理的规范依赖
虽然重写了__str__返回自定义的self.error_message,但Python的异常处理流程(比如traceback模块打印栈信息、某些第三方日志工具)可能会优先读取父类的args或内部消息属性。如果父类未初始化,这些工具就无法获取到有效消息,导致你看到的“错误消息完全不打印”的情况。异常对象的完整性
当你raise一个异常时,Python要求异常对象符合标准异常的规范。父类Exception的__init__是确保对象状态完整的关键步骤,缺失它会导致异常对象不符合规范,进而影响整个异常处理流程的正常运行。
测试验证
可以通过以下代码直观看到差异:
import sys def error_message_details(error, error_detail:sys): _,_,exc_tb = error_detail.exc_info() file_name = exc_tb.tb_frame.f_code.co_filename lineNo = exc_tb.tb_lineno error_message = "error occured in script [{0}] on line number [{1}]; error message [{2}]".format( file_name, lineNo, str(error) ) return error_message # 带super的版本 class CustomExceptionWithSuper(Exception): def __init__(self, error_message, error_detail:sys): super().__init__(error_message) self.error_message = error_message_details(error_message,error_detail) def __str__(self): return self.error_message # 不带super的版本 class CustomExceptionWithoutSuper(Exception): def __init__(self, error_message, error_detail:sys): self.error_message = error_message_details(error_message,error_detail) def __str__(self): return self.error_message # 测试 try: 1 / 0 except ZeroDivisionError as e: print("=== 带super的异常输出 ===") try: raise CustomExceptionWithSuper(str(e), sys) except CustomExceptionWithSuper as ce: print(ce) print("异常的args属性:", ce.args) print("\n=== 不带super的异常输出 ===") try: raise CustomExceptionWithoutSuper(str(e), sys) except CustomExceptionWithoutSuper as ce: print(ce) print("异常的args属性:", ce.args)
运行后会发现:
- 带super的版本,
ce.args会包含传入的原始错误消息; - 不带super的版本,
ce.args是空元组。
虽然你的__str__能返回自定义消息,但如果有代码依赖args属性,就会出现问题——这也是为什么有些场景下去掉super后错误消息不显示的原因。
内容的提问来源于stack exchange,提问作者Prithvi Shah

