python中使用_setattr_()

__setattr__用于控制属性赋值,每次设置属性时触发,可实现验证、只读等逻辑,需通过super().__setattr__或__dict__避免递归。

在 Python 中,__setattr__ 是一个特殊方法,用于控制对象属性的赋值行为。每当尝试设置对象的某个属性时,这个方法就会被调用。通过自定义 __setattr__,你可以实现属性验证、只读属性、动态属性管理等高级功能。

基本用法

__setattr__(self, name, value) 接收三个参数:

  • self:实例本身
  • name:要设置的属性名(字符串)
  • value:要设置的属性值

每次执行 self.attr = valuesetattr(obj, 'attr', value) 都会触发它。

示例:

class Person:
    def __init__(self, name):
        self.name = name  # 这里也会触发 __setattr__
def __setattr__(self, name, value):
    print(f"正在设置属性: {name} = {value}")
    super().__setattr__(name, value)

p = Person("Alice") p.age = 25

输出:

正在设置属性: name = Alice
正在设置属性: age = 25

防止无限递归

__setattr__ 内部直接使用 self.name = value 会导致无限递归,因为它又会调用 __setattr__

正确做法是使用父类的 __setattr__ 或操作实例的 __dict__

  • super().__setattr__('name', value)
  • self.__dict__['name'] = value

错误示例(会报 RecursionError):

def __setattr__(self, name, value):
    self.name = value  # 错误!无限递归

实现属性验证或只读字段

你可以利用 __setattr__ 拦截非法赋值。

例如,限制某属性只能为特定类型:

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
def __setattr__(self, name, value):
    if name == "celsius":
        if not isinstance(value, (int, float)):
            raise TypeError("温度必须是数字")
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        super().__setattr__("_celsius", value)
    else:
        super().__setattr__(name, value)

@property
def celsius(self):
    return self._celsius

t = Temperature(25) t.celsius = 30 # 正常

t.celsius = "abc" # 抛出 TypeError

控制动态属性

有时你想禁止随意添加属性,只允许预定义的几个:

class StrictPerson:
    __slots__ = ['name', 'age']  # 更推荐用 __slots__
# 或者用 __setattr__ 实现类似效果
def __setattr__(self, name, value):
    if name not in {'name', 'age'}:
        raise AttributeError(f"不能设置属性 '{name}'")
    super().__setattr__(name, value)

基本上就这些。只要记住:每次赋值都会触发它,别在内部直接赋值导致循环,用 super() 或 __dict__ 安全操作。合理使用能增强类的行为控制。