Python抛出异常并记录日志时如何减少重复样板代码
解决方案
以下三种方案按适用场景从简单到复杂排序:
方案1:本地变量复用(适配少量零散校验场景)
直接将重复的错误信息定义为本地变量,两处逻辑共用同一个变量即可,无需调整现有代码结构,改造成本最低。
@start_date.setter def start_date(self, val: dt.datetime): if not isinstance(val, dt.datetime): # 错误信息统一定义,修改只需调整一处 err_msg = f'Expecting datetime as start date, got {type(val)} instead.' # 补充exc_info=True输出调用栈,替换原不合理的logger.exception使用 logger.error(err_msg, exc_info=True) raise TypeError(err_msg) self.__start_date = val
方案2:封装通用校验函数(适配多位置复用同类型校验)
如果项目中多处需要做类型校验、日志上报、异常抛出的逻辑,可以把这部分统一封装为工具函数,彻底避免重复的判断代码。
def validate_type(value, expected_type, prop_name, logger): if not isinstance(value, expected_type): err_msg = f'Expecting {expected_type.__name__} as {prop_name}, got {type(value).__name__} instead.' logger.error(err_msg, exc_info=True) raise TypeError(err_msg) # setter中直接调用即可 @start_date.setter def start_date(self, val: dt.datetime): validate_type(val, dt.datetime, "start date", logger) self.__start_date = val
后续如果要新增其他属性的类型校验,只需要一行调用即可,不需要重复写判断、日志、抛异常的逻辑。
方案3:自定义描述符(适配类存在大量需校验属性的场景)
如果你的类有多个属性都需要做类似的类型校验,可以自定义描述符封装完整的属性存取逻辑,连@property的重复定义都可以省去,一劳永逸。
class TypedProperty: def __init__(self, expected_type): self.expected_type = expected_type self.attr_name = None # 自动获取绑定的属性名 def __set_name__(self, owner, name): self.attr_name = name def __get__(self, instance, owner): if instance is None: return self return instance.__dict__.get(f"_{self.attr_name}") def __set__(self, instance, value): if not isinstance(value, self.expected_type): err_msg = f'Expecting {self.expected_type.__name__} as {self.attr_name}, got {type(value).__name__} instead.' logger.error(err_msg, exc_info=True) raise TypeError(err_msg) instance.__dict__[f"_{self.attr_name}"] = value # 类定义直接使用描述符,不需要额外写getter、setter @dataclass class Foo: start_date: dt.datetime = TypedProperty(dt.datetime) # 新增其他需要校验的属性只需要一行定义 # end_date: dt.datetime = TypedProperty(dt.datetime)
如果后续需要扩展校验规则,比如增加非空校验、范围校验等,只需要修改描述符的__set__方法即可,所有用到的属性会自动生效。
内容的提问来源于stack exchange,提问作者NotAName
相关产品推荐
相关产品推荐

