类属性__setattr__设置疑问:阻止新增属性与调用逻辑
问题解答
1. 阻止设置新类属性的简单方法
要禁止给类本身添加新属性,核心是利用元类——Python里所有类都是元类的实例,给类设置属性时,实际调用的是元类的__setattr__方法。
方案1:禁止新增类属性,允许修改已有属性
class FrozenMeta(type): def __setattr__(cls, key, value): if key not in cls.__dict__: raise PermissionError("不允许添加新的类属性") super().__setattr__(key, value) # 使用该元类创建目标类 class MyClass(metaclass=FrozenMeta): existing_attr = 10 # 正常修改已有属性 MyClass.existing_attr = 20 # 新增属性会触发错误 MyClass.new_attr = 30 # PermissionError: 不允许添加新的类属性
方案2:彻底禁止修改任何类属性
class FrozenMeta(type): def __setattr__(cls, key, value): raise PermissionError("禁止修改任何类属性")
注意:如果只是想限制实例的属性,用__slots__更简单,但它不影响类本身的属性操作。
2. 为什么setattr(Derived, "test1", 1)没触发Base的__setattr__?
你混淆了两类__setattr__的作用范围:
- 类里定义的
__setattr__是实例方法,只负责处理该类创建的实例对象的属性设置,和类本身无关。 Derived本身是type类的实例(Python默认元类是type),给它设置属性时,调用的是type的__setattr__,自然不会触发Base或Derived里定义的__setattr__。
再看你代码里的其他调用:
Derived.__setattr__(Derived, "test2", 2):这是手动把Derived类作为self参数,传给了Derived的__setattr__方法,所以才触发了你在__init_subclass__里定义的自定义逻辑。Base.__setattr__(Derived, "test3", 3):这是直接调用Base的__setattr__,并把Derived作为self传入,所以触发了Base里的异常。
总结:类的__setattr__管实例的属性,类本身的属性操作由元类的__setattr__负责。
内容的提问来源于stack exchange,提问作者deponovo
相关产品推荐
相关产品推荐

