You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否使用__slots__限制Python子类属性?如何阻止继承父类__dict__?

如何在继承无__slots__父类的子类中禁止添加新属性

当子类继承自未定义__slots__的父类时,子类的__slots__无法阻止动态添加新属性——原因是父类实例自带__dict__,子类实例会继承这一特性,允许任意扩展属性。要解决这个问题,有两种可行方案:

方案1:重写__setattr__方法

通过自定义属性设置逻辑,检查要添加的属性是否属于子类__slots__的范围,超出范围则抛出错误:

class Whatever:
    pass

class Thing(Whatever):
    __slots__ = ('a', 'b')
    
    def __setattr__(self, name, value):
        if name not in self.__slots__:
            raise AttributeError(f"'Thing' object has no attribute '{name}'")
        super().__setattr__(name, value)

# 测试
thing = Thing()
thing.a = 1  # 正常执行
thing.c = 'hello'  # 抛出AttributeError

这种方式无需修改父类代码,完全在子类内部实现约束。

方案2:给父类添加__slots__

如果有权限修改父类,可以给父类定义空的__slots__,这样子类的__slots__就能原生生效,子类实例不会生成__dict__:

class Whatever:
    __slots__ = ()  # 父类定义空槽

class Thing(Whatever):
    __slots__ = ('a', 'b')

thing = Thing()
thing.c = 'hello'  # 抛出AttributeError

这种方式更贴合Python原生__slots__的设计逻辑,但依赖对父类的修改权限。


关于里氏替换原则的讨论

你提到的场景确实涉及里氏替换原则(LSP)的思考:

  • 经典的「圆继承椭圆」反例中,圆的约束比椭圆更严格,替换后无法满足椭圆的行为契约(比如修改半轴),直接违反了LSP。
  • 回到当前场景:父类允许动态添加任意属性,子类却禁止该行为。如果代码中存在依赖父类「可动态扩展属性」的逻辑,子类替换父类后会触发错误,这确实违反了LSP——子类没有遵守父类的行为契约。

不过Python的动态特性让这个问题变得模糊:「允许添加任意属性」更像是动态语言的默认特性,而非父类明确声明的契约。如果你的子类是为了实现更严格的属性约束,或许更适合用组合而非继承——让子类持有父类实例,而非直接继承,这样既复用父类功能,又能独立约束子类的属性行为。

内容的提问来源于stack exchange,提问作者Manngo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 07:57:19