python __getattr__和__setattr__

本文介绍如何在Python中创建自定义字典类,并通过__getattr__和__setattr__方法实现对字典类实例属性的灵活获取与设置。具体演示了如何通过这两个特殊方法使得实例能够像普通属性那样被访问和修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

__getattr__:当使用点号获取实例属性时,如果属性不存在就自动调用__getattr__方法。
__setattr__:当设置类实例属性时自动调用,如j.name=5 就会调用__setattr__方法 。
self.[name]=5因为这个类是从dict继承来的,是dict的子类所以 self[attr]=value 相当于调用dict的下标方法与 a={} ; a[attr]=value意思一样。

案例:

class Dict(dict):

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

d = Dict(a=1, b=2)
print (d['a'])
print (d.a) #调用类中原本没有定义的属性时候,调用__getattr__
d.a = 100 #对实例的属性进行赋值的时候调用__setattr__
print (d['a'])

运行结果:

1
1
100
<think>嗯,用户想了解Python中的__setattr__方法的含义使用场景。首先,我需要回忆一下这个方法的定义。__setattr__是一个特殊方法,用于控制属性的设置行为。当给对象的属性赋值时,比如obj.attr= value,这个方法会被调用。接下来,我需要确定用户可能需要的详细信息。用户可能想知道这个方法的基本作用,如何正确使用它,以及常见的应用场景。根据提供的引用资料,引用[1]提到__setattr__用于控制属性的设置,引用[2]中的示例代码展示了如何在类中定义__setattr__,并且必须调用父类的方法,比如super().__setattr__,否则会导致递归错误。引用[3]讨论了使用__setattr__进行数据封装懒加载,而引用[4]指出__setattr__拦截所有属性设置,而__getattr__只处理未定义的属性。然后,我需要组织这些信息。首先解释__setattr__的作用,然后给出基本用法示例,强调必须调用父类实现。接着,说明使用场景,比如属性验证、动态计算属性、惰性初始化、防止意外覆盖属性别名等。每个场景都需要例子,比如在属性验证中检查值是否为整数,否则抛出异常。还要注意用户可能的误区,比如在__setattr__内部直接赋值会导致递归,必须使用super().__setattr__。引用[2]的示例代码中,每次设置属性时都会打印信息,但通过super()避免了递归问题。最后,生成相关问题,帮助用户进一步学习,比如与__getattr__的区别,避免递归的方法,实际应用案例,与property的比较,以及如何实现只读属性。这些问题需要覆盖用户可能深入学习的方面。</think>### Python中`__setattr__`方法的含义及使用场景 #### 一、`__setattr__`方法的含义 `__setattr__`是Python类的特殊方法,用于**拦截并控制属性的赋值操作**。当通过`obj.attr = value`设置属性时,该方法会被自动调用,开发者可在此实现自定义逻辑(如验证、动态计算等)[^1][^3]。 #### 二、基本用法 1. **语法定义**: ```python def __setattr__(self, key, value): # 自定义逻辑 super().__setattr__(key, value) # 必须调用父类方法避免递归 ``` 2. **示例**: ```python class User: def __init__(self, name): self.name = name # 触发__setattr__ def __setattr__(self, key, value): print(f"设置属性 {key} = {value}") super().__setattr__(key, value) # 关键步骤[^2] user = User("Alice") # 输出:设置属性 name = Alice ``` #### 三、核心使用场景 1. **属性验证** 在赋值前检查值的有效性: ```python class Temperature: def __setattr__(self, key, value): if key == "celsius" and value < -273.15: raise ValueError("温度不能低于绝对零度") super().__setattr__(key, value) ``` 2. **动态计算属性** 自动生成关联属性: ```python class Rectangle: def __init__(self, width, height): self.width = width self.height = height def __setattr__(self, key, value): super().__setattr__(key, value) if key in ("width", "height"): # 任一属性变化时更新面积 super().__setattr__("area", self.width * self.height) ``` 3. **惰性初始化** 延迟资源加载: ```python class LazyData: def __getattr__(self, name): if name == "data": print("首次加载大数据") self.data = load_from_database() # 触发__setattr__ return self.data ``` 4. **防止意外覆盖** 保护关键属性: ```python class SafeConfig: def __setattr__(self, key, value): if key == "api_key": raise AttributeError("API密钥不可直接修改") super().__setattr__(key, value) ``` 5. **属性别名映射** 实现字段重命名: ```python class AliasMapper: def __setattr__(self, key, value): if key == "old_name": key = "new_name" # 自动转换旧属性名 super().__setattr__(key, value) ``` #### 四、注意事项 - **递归陷阱**:在`__setattr__`中直接使用`self.key = value`会导致无限递归,必须通过`super()`调用父类方法[^2][^4]。 - **性能影响**:频繁拦截属性操作可能影响效率,需权衡使用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值