如何检查子类待定义的属性/方法名未被父类预先占用?
在Python子类继承开发中要避免新增成员覆盖父类同名内容,可通过以下3种常用方案实现,同时解决你示例中的断言取值问题:你原来的代码中不知道断言该填什么,本质是不需要检查正在定义的子类,我们只需要确认父类不存在你要新增的这个成员名,就不会出现覆盖问题,直接把父类传入hasattr即可。
方案1:手动前置检查(最简单,适合少量方法的场景)
直接在定义方法前检查父类是否存在同名成员,无需复杂语法:
class MyFoo(Foo): # 直接检查父类Foo是否存在待定义的mymethod assert not hasattr(Foo, 'mymethod'), "父类Foo已存在mymethod方法,禁止覆盖" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def mymethod(self): # 此处逻辑不会覆盖父类同名方法 ...
如果是多继承场景,直接遍历所有基类检查即可:
class MyFoo(Foo, Bar, Baz): # 遍历所有直接父类检查 for base in (Foo, Bar, Baz): assert not hasattr(base, 'mymethod'), f"父类{base.__name__}已存在mymethod方法,禁止覆盖" def mymethod(self): ...
方案2:使用__init_subclass__钩子自动全量检查(适合大型项目,无需手动写断言)
Python 3.6及以上版本支持__init_subclass__钩子,会在子类定义完成后自动触发,我们可以封装一个公共父类实现自动检查逻辑,所有业务父类继承该公共类即可:
class NoOverrideBase: def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) # 遍历子类自身定义的所有属性 for attr_name in cls.__dict__: # 跳过Python自带的魔法方法,如有需要可删除该判断 if attr_name.startswith('__') and attr_name.endswith('__'): continue # 遍历整个父类继承链检查是否有重名成员 for base in cls.__mro__[1:]: if attr_name in base.__dict__: raise TypeError(f"子类{cls.__name__}试图覆盖父类{base.__name__}的已有成员{attr_name},操作禁止") # 业务父类继承禁止覆盖的基类即可 class Foo(NoOverrideBase): def mymethod(self): pass # 定义子类时如果出现同名方法,会在类定义阶段直接抛出错误 class MyFoo(Foo): # 此处定义mymethod会直接触发TypeError def mymethod(self): ...
方案3:方法装饰器实现粒度更灵活的检查
如果不需要全量禁止覆盖,只针对个别需要保护的方法做检查,可以自定义装饰器实现:
def no_override(parent_cls): def decorator(func): func_name = func.__name__ assert not hasattr(parent_cls, func_name), f"父类{parent_cls.__name__}已存在方法{func_name},禁止覆盖" return func return decorator class MyFoo(Foo): @no_override(Foo) def mymethod(self): # 如果Foo已存在mymethod,装饰器会在类定义阶段直接抛出断言错误 ...
内容的提问来源于stack exchange,提问作者nigel222
相关产品推荐
相关产品推荐

