Python中property与__getattr__共存及阻止新增属性问题
解决方案
要实现仅允许在实例化时通过指定参数添加额外可读写属性,同时禁止后续新增自定义属性,可以通过以下方式修改代码,同时兼容已有的property:
class Person: __slots__ = ["_name", "_allowed_extra_attr"] def __init__(self, name, extra_arg): # 记录允许的额外属性名 self._allowed_extra_attr = extra_arg # 初始化内置属性 self._name = name # 初始化额外属性 setattr(self, extra_arg, None) @property def name(self): return self._name @name.setter def name(self, value): self._name = value def __setattr__(self, name, value): # 允许设置的属性:内置私有属性、允许的额外属性 allowed_attrs = {self._allowed_extra_attr, "_name", "_allowed_extra_attr"} if name in allowed_attrs: super().__setattr__(name, value) else: raise AttributeError(f"Cannot set attribute '{name}': only pre-defined attributes are allowed") # 测试示例 person = Person("gribouille", "hello") print(person.name) # 正常读取property person.name = "new_name" # 正常修改property print(person.name) person.hello = "world" # 正常修改额外属性 print(person.hello) # 尝试新增自定义属性会报错 try: person.custom_attribute = "value" except AttributeError as e: print(e) # 输出: Cannot set attribute 'custom_attribute': only pre-defined attributes are allowed
关键改动说明
- 调整
__slots__:移除__dict__,新增_allowed_extra_attr用于存储实例化时指定的额外属性名。这样默认会阻止所有未在__slots__中声明的属性,避免用户随意新增。 - 重写
__setattr__:- 仅允许设置三类属性:
_name(对应nameproperty的底层存储)、_allowed_extra_attr(记录允许的额外属性名)、以及实例化时指定的extra_arg属性。 - 其他属性设置直接抛出
AttributeError,阻止自定义属性添加。
- 仅允许设置三类属性:
- 兼容
property:name的setter本质是修改_name,而_name在允许的属性列表中,因此不会和__setattr__冲突。
扩展提示
如果需要支持多个额外属性,只需将extra_arg改为列表/元组,在__init__中遍历初始化,并在__setattr__中判断属性是否在允许的列表里即可。
内容的提问来源于stack exchange,提问作者Gribouille
相关产品推荐
相关产品推荐

